<!-- build time:Sun Nov 24 2019 22:25:17 GMT+0800 (China Standard Time) --><!DOCTYPE html><html lang="zh"><head><meta charset="utf-8"><title>Vuex的基本概念和使用方法 - Note?Note!</title><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="description" content="什么是VuexVuex是一个Vue.js的扩展库，是一个关于状态管理模式的库，提供的作用主要是用于Vue应用的全局数据管理。安装vue dev tool extension for chrome 后，Vuex可以使用Chrome DevTool中进行调试。"><meta name="keywords" content="Vue,Vuex"><meta property="og:type" content="article"><meta property="og:title" content="Vuex的基本概念和使用方法"><meta property="og:url" content="http:&#x2F;&#x2F;www.borgor.cn&#x2F;2019-06-11&#x2F;e9c1a7e6.html"><meta property="og:site_name" content="Note?Note!"><meta property="og:description" content="什么是VuexVuex是一个Vue.js的扩展库，是一个关于状态管理模式的库，提供的作用主要是用于Vue应用的全局数据管理。安装vue dev tool extension for chrome 后，Vuex可以使用Chrome DevTool中进行调试。"><meta property="og:locale" content="zh-CN"><meta property="og:image" content="https:&#x2F;&#x2F;imgs.borgor.cn&#x2F;imgs20190625083539.png"><meta property="og:updated_time" content="2019-11-19T05:53:25.209Z"><meta name="twitter:card" content="summary"><meta name="twitter:image" content="https:&#x2F;&#x2F;imgs.borgor.cn&#x2F;imgs20190625083539.png"><link rel="icon" href="/favicon.ico"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css"><link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/font-awesome/5.4.1/css/all.min.css"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:400,600|Source+Code+Pro"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-light.min.css"><style>body>.footer,body>.navbar,body>.section{opacity:0}</style><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/1.6.8/css/lightgallery.min.css"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/justifiedGallery/3.7.0/css/justifiedGallery.min.css"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.css"><link rel="stylesheet" href="/css/back-to-top.css"><script>var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="//hm.baidu.com/hm.js?6cecff6d18ae0c22fd7ac294c80fe7c0";var c=document.getElementsByTagName("script")[0];c.parentNode.insertBefore(e,c)}()</script><link rel="stylesheet" href="/css/progressbar.css"><script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.0.2/pace.min.js"></script><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><link rel="stylesheet" href="/css/style.css"></head><body class="is-2-column"><nav class="navbar navbar-main"><div class="container"><div class="navbar-brand is-flex-center"><a class="navbar-item navbar-logo" href="/"><img src="https://imgs.borgor.cn/imgs20190625111723.jpg" alt="Vuex的基本概念和使用方法" height="28"></a></div><div class="navbar-menu"><div class="navbar-start"><a class="navbar-item" href="/">首页</a> <a class="navbar-item" href="/archives">归档</a> <a class="navbar-item" href="/categories">分类</a> <a class="navbar-item" href="/tags">标签</a> <a class="navbar-item" href="/readinglist">书单</a></div><div class="navbar-end"><a class="navbar-item is-hidden-tablet catalogue" title="目录" href="javascript:;" target="_blank" rel="noopener"><i class="fas fa-list-ul"></i> </a><a class="navbar-item search" title="搜索" href="javascript:;" target="_blank" rel="noopener"><i class="fas fa-search"></i></a></div></div></div></nav><section class="section"><div class="container"><div class="columns"><div class="column is-8-tablet is-9-desktop is-9-widescreen has-order-2 column-main"><div class="card"><div class="card-image"><span class="image is-7by1"><img class="thumbnail" src="https://imgs.borgor.cn/imgs20190625083539.png" alt="Vuex的基本概念和使用方法"></span></div><div class="card-content article"><div class="level article-meta is-size-7 is-uppercase is-mobile is-overflow-x-auto"><div class="level-left"><time class="level-item has-text-grey" datetime="2019-06-11T03:06:56.000Z">2019-06-11</time><div class="level-item"><a class="has-link-grey -link" href="/categories/Development/">Development</a>&nbsp;/&nbsp;<a class="has-link-grey -link" href="/categories/Development/JavaScript/">JavaScript</a></div><span class="level-item has-text-grey">1 小时 读完 (大约 8134 个字) </span><span class="level-item has-text-grey" id="busuanzi_container_page_pv"><i class="far fa-eye"></i> <span id="busuanzi_value_page_pv">0</span>次访问</span></div></div><h1 class="title is-size-3 is-size-4-mobile has-text-weight-normal">Vuex的基本概念和使用方法</h1><div class="content"><h1 id="什么是Vuex"><a href="#什么是Vuex" class="headerlink" title="什么是Vuex"></a>什么是Vuex</h1><p><code>Vuex</code>是一个<code>Vue.js</code>的扩展库，是一个关于状态管理模式的库，提供的作用主要是用于Vue应用的全局数据管理。</p><p>安装<em>vue dev tool extension for chrome</em> 后，<code>Vuex</code>可以使用<em>Chrome DevTool</em>中进行调试。</p><a id="more"></a><p><img src="https://imgs.borgor.cn/imgs/imgs-Vuex%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5%E5%92%8C%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95-2019-6-25-11-1-27.png" alt></p><h1 id="Vuex的安装"><a href="#Vuex的安装" class="headerlink" title="Vuex的安装"></a>Vuex的安装</h1><h2 id="Direct-Download-CDN"><a href="#Direct-Download-CDN" class="headerlink" title="Direct Download / CDN"></a>Direct Download / CDN</h2><p>直接使用脚本加载</p><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/path/to/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span><br><span class="line"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/path/to/vuex.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="NPM"><a href="#NPM" class="headerlink" title="NPM"></a>NPM</h2><figure class="highlight bash hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install vuex --save</span><br></pre></td></tr></table></figure><h2 id="Yarn"><a href="#Yarn" class="headerlink" title="Yarn"></a>Yarn</h2><figure class="highlight bash hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ yarn add vuex</span><br></pre></td></tr></table></figure><p>在应用入口处，可以使用<em>Vue.use(Vuex)</em>加载</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span></span><br><span class="line"><span class="hljs-keyword">import</span> Vuex <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span></span><br><span class="line"></span><br><span class="line">Vue.use(Vuex)</span><br></pre></td></tr></table></figure><h1 id="Vuex的基础概念"><a href="#Vuex的基础概念" class="headerlink" title="Vuex的基础概念"></a>Vuex的基础概念</h1><h2 id="State-—-状态"><a href="#State-—-状态" class="headerlink" title="State — 状态"></a>State — 状态</h2><p>Vuex 使用<strong>单一状态树</strong>——是的，用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (<a href="https://en.wikipedia.org/wiki/Single_source_of_truth" target="_blank" rel="noopener">SSOT</a>)”而存在。这也意味着，每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段，在调试的过程中也能轻易地取得整个当前应用状态的快照。</p><p>单状态树和模块化并不冲突——在后面的章节里我们会讨论如何将状态和状态变更事件分布到各个子模块中。</p><h3 id="在-Vue-组件中获得-Vuex-状态"><a href="#在-Vue-组件中获得-Vuex-状态" class="headerlink" title="在 Vue 组件中获得 Vuex 状态"></a>在 Vue 组件中获得 Vuex 状态</h3><p>那么我们如何在 Vue 组件中展示状态呢？由于 Vuex 的状态存储是响应式的，从 store 实例中读取状态最简单的方法就是在<a href="https://cn.vuejs.org/guide/computed.html" target="_blank" rel="noopener">计算属性</a>中返回某个状态：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// 创建一个 Counter 组件</span></span><br><span class="line"><span class="hljs-keyword">const</span> Counter = &#123;</span><br><span class="line">  template: <span class="hljs-string">`&lt;div&gt;&#123;&#123; count &#125;&#125;&lt;/div&gt;`</span>,</span><br><span class="line">  computed: &#123;</span><br><span class="line">    count () &#123;</span><br><span class="line">      <span class="hljs-keyword">return</span> store.state.count</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>每当 <code>store.state.count</code> 变化的时候, 都会重新求取计算属性，并且触发更新相关联的 DOM。</p><p>然而，这种模式导致组件依赖全局状态单例。在模块化的构建系统中，在每个需要使用 state 的组件中需要频繁地导入，并且在测试组件时需要模拟状态。</p><p>Vuex 通过 <code>store</code> 选项，提供了一种机制将状态从根组件“注入”到每一个子组件中（需调用 <code>Vue.use(Vuex)</code>）：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="hljs-string">'#app'</span>,</span><br><span class="line">  <span class="hljs-comment">// 把 store 对象提供给 “store” 选项，这可以把 store 的实例注入所有的子组件</span></span><br><span class="line">  store,</span><br><span class="line">  components: &#123; Counter &#125;,</span><br><span class="line">  template: <span class="hljs-string">`</span></span><br><span class="line"><span class="hljs-string">    &lt;div class="app"&gt;</span></span><br><span class="line"><span class="hljs-string">      &lt;counter&gt;&lt;/counter&gt;</span></span><br><span class="line"><span class="hljs-string">    &lt;/div&gt;</span></span><br><span class="line"><span class="hljs-string">  `</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>通过在根实例中注册 <code>store</code> 选项，该 store 实例会注入到根组件下的所有子组件中，且子组件能通过 <code>this.$store</code> 访问到。让我们更新下 <code>Counter</code> 的实现：</p><h3 id="mapState-辅助函数"><a href="#mapState-辅助函数" class="headerlink" title="mapState 辅助函数"></a><code>mapState</code> 辅助函数</h3><p>当一个组件需要获取多个状态时候，将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题，我们可以使用 <code>mapState</code> 辅助函数帮助我们生成计算属性，让你少按几次键：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// 在单独构建的版本中辅助函数为 Vuex.mapState</span></span><br><span class="line"><span class="hljs-keyword">import</span> &#123; mapState &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  computed: mapState(&#123;</span><br><span class="line">    <span class="hljs-comment">// 箭头函数可使代码更简练</span></span><br><span class="line">    count: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.count,</span><br><span class="line"></span><br><span class="line">    <span class="hljs-comment">// 传字符串参数 'count' 等同于 `state =&gt; state.count`</span></span><br><span class="line">    countAlias: <span class="hljs-string">'count'</span>,</span><br><span class="line"></span><br><span class="line">    <span class="hljs-comment">// 为了能够使用 `this` 获取局部状态，必须使用常规函数</span></span><br><span class="line">    countPlusLocalState (state) &#123;</span><br><span class="line">      <span class="hljs-keyword">return</span> state.count + <span class="hljs-keyword">this</span>.localCount</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>当映射的计算属性的名称与 state 的子节点名称相同时，我们也可以给 <code>mapState</code> 传一个字符串数组。</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">computed: mapState([</span><br><span class="line">  <span class="hljs-comment">// 映射 this.count 为 store.state.count</span></span><br><span class="line">  <span class="hljs-string">'count'</span></span><br><span class="line">])</span><br></pre></td></tr></table></figure><h3 id="对象展开运算符"><a href="#对象展开运算符" class="headerlink" title="对象展开运算符"></a>对象展开运算符</h3><p><code>mapState</code> 函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢？通常，我们需要使用一个工具函数将多个对象合并为一个，以使我们可以将最终对象传给 <code>computed</code> 属性。但是自从有了<a href="https://github.com/sebmarkbage/ecmascript-rest-spread" target="_blank" rel="noopener">对象展开运算符</a>（现处于 ECMAScript 提案 stage-4 阶段），我们可以极大地简化写法：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">computed: &#123;</span><br><span class="line">  localComputed () &#123; <span class="hljs-comment">/* ... */</span> &#125;,</span><br><span class="line">  <span class="hljs-comment">// 使用对象展开运算符将此对象混入到外部对象中</span></span><br><span class="line">  ...mapState(&#123;</span><br><span class="line">    <span class="hljs-comment">// ...</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="组件仍然保有局部状态"><a href="#组件仍然保有局部状态" class="headerlink" title="组件仍然保有局部状态"></a>组件仍然保有局部状态</h3><p>使用 Vuex 并不意味着你需要将<strong>所有的</strong>状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试，但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件，最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。</p><h2 id="Getters-—-获取器"><a href="#Getters-—-获取器" class="headerlink" title="Getters — 获取器"></a>Getters — 获取器</h2><p>有时候我们需要从 store 中的 state 中派生出一些状态，例如对列表进行过滤并计数：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">computed: &#123;</span><br><span class="line">  doneTodosCount () &#123;</span><br><span class="line">    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.$store.state.todos.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> todo.done).length</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果有多个组件需要用到此属性，我们要么复制这个函数，或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。</p><p>Vuex 允许我们在 store 中定义“getter”（可以认为是 store 的计算属性）。就像计算属性一样，getter 的返回值会根据它的依赖被缓存起来，且只有当它的依赖值发生了改变才会被重新计算。</p><p>Getter 接受 state 作为其第一个参数：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state: &#123;</span><br><span class="line">    todos: [</span><br><span class="line">      &#123; <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'...'</span>, <span class="hljs-attr">done</span>: <span class="hljs-literal">true</span> &#125;,</span><br><span class="line">      &#123; <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'...'</span>, <span class="hljs-attr">done</span>: <span class="hljs-literal">false</span> &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line">  getters: &#123;</span><br><span class="line">    doneTodos: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="hljs-keyword">return</span> state.todos.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> todo.done)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="通过属性访问"><a href="#通过属性访问" class="headerlink" title="通过属性访问"></a>通过属性访问</h3><p>Getter 会暴露为 <code>store.getters</code> 对象，你可以以属性的形式访问这些值：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">store.getters.doneTodos <span class="hljs-comment">// -&gt; [&#123; id: 1, text: '...', done: true &#125;]</span></span><br></pre></td></tr></table></figure><p>Getter 也可以接受其他 getter 作为第二个参数：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">getters: &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  doneTodosCount: <span class="hljs-function">(<span class="hljs-params">state, getters</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="hljs-keyword">return</span> getters.doneTodos.length</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">store.getters.doneTodosCount <span class="hljs-comment">// -&gt; 1</span></span><br></pre></td></tr></table></figure><p>我们可以很容易地在任何组件中使用它：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">computed: &#123;</span><br><span class="line">  doneTodosCount () &#123;</span><br><span class="line">    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.$store.getters.doneTodosCount</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意，getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。</p><h3 id="通过方法访问"><a href="#通过方法访问" class="headerlink" title="通过方法访问"></a>通过方法访问</h3><p>你也可以通过让 getter 返回一个函数，来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">getters: &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  getTodoById: <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="hljs-keyword">return</span> state.todos.find(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> todo.id === id)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">store.getters.getTodoById(<span class="hljs-number">2</span>) <span class="hljs-comment">// -&gt; &#123; id: 2, text: '...', done: false &#125;</span></span><br></pre></td></tr></table></figure><p>注意，getter 在通过方法访问时，每次都会去进行调用，而不会缓存结果。</p><h3 id="mapGetters-辅助函数"><a href="#mapGetters-辅助函数" class="headerlink" title="mapGetters 辅助函数"></a><code>mapGetters</code> 辅助函数</h3><p><code>mapGetters</code> 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">import</span> &#123; mapGetters &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  computed: &#123;</span><br><span class="line">  <span class="hljs-comment">// 使用对象展开运算符将 getter 混入 computed 对象中</span></span><br><span class="line">    ...mapGetters([</span><br><span class="line">      <span class="hljs-string">'doneTodosCount'</span>,</span><br><span class="line">      <span class="hljs-string">'anotherGetter'</span>,</span><br><span class="line">      <span class="hljs-comment">// ...</span></span><br><span class="line">    ])</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果你想将一个 getter 属性另取一个名字，使用对象形式：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mapGetters(&#123;</span><br><span class="line">  <span class="hljs-comment">// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`</span></span><br><span class="line">  doneCount: <span class="hljs-string">'doneTodosCount'</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="Mutations-—-修改器"><a href="#Mutations-—-修改器" class="headerlink" title="Mutations — 修改器"></a>Mutations — 修改器</h2><p>更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件：每个 mutation 都有一个字符串的 <strong>事件类型 (type)</strong> 和 一个 <strong>回调函数 (handler)</strong>。这个回调函数就是我们实际进行状态更改的地方，并且它会接受 state 作为第一个参数：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state: &#123;</span><br><span class="line">    count: <span class="hljs-number">1</span></span><br><span class="line">  &#125;,</span><br><span class="line">  mutations: &#123;</span><br><span class="line">    increment (state) &#123;</span><br><span class="line">      <span class="hljs-comment">// 变更状态</span></span><br><span class="line">      state.count++</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>你不能直接调用一个 mutation handler。这个选项更像是事件注册：“当触发一个类型为 <code>increment</code> 的 mutation 时，调用此函数。”要唤醒一个 mutation handler，你需要以相应的 type 调用 <strong>store.commit</strong> 方法：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">store.commit(<span class="hljs-string">'increment'</span>)</span><br></pre></td></tr></table></figure><h3 id="提交载荷（Payload）"><a href="#提交载荷（Payload）" class="headerlink" title="提交载荷（Payload）"></a>提交载荷（Payload）</h3><p>你可以向 <code>store.commit</code> 传入额外的参数，即 mutation 的 <strong>载荷（payload）</strong>：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// ...</span></span><br><span class="line">mutations: &#123;</span><br><span class="line">  increment (state, n) &#123;</span><br><span class="line">    state.count += n</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">store.commit(<span class="hljs-string">'increment'</span>, <span class="hljs-number">10</span>)</span><br></pre></td></tr></table></figure><p>在大多数情况下，载荷应该是一个对象，这样可以包含多个字段并且记录的 mutation 会更易读：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// ...</span></span><br><span class="line">mutations: &#123;</span><br><span class="line">  increment (state, payload) &#123;</span><br><span class="line">    state.count += payload.amount</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">store.commit(<span class="hljs-string">'increment'</span>, &#123;</span><br><span class="line">  amount: <span class="hljs-number">10</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="对象风格的提交方式"><a href="#对象风格的提交方式" class="headerlink" title="对象风格的提交方式"></a>对象风格的提交方式</h3><p>提交 mutation 的另一种方式是直接使用包含 <code>type</code> 属性的对象：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">store.commit(&#123;</span><br><span class="line">  type: <span class="hljs-string">'increment'</span>,</span><br><span class="line">  amount: <span class="hljs-number">10</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>当使用对象风格的提交方式，整个对象都作为载荷传给 mutation 函数，因此 handler 保持不变：</p><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">mutations: &#123;</span><br><span class="line">  increment (state, payload) &#123;</span><br><span class="line">    state.count += payload.amount</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Mutation-需遵守-Vue-的响应规则"><a href="#Mutation-需遵守-Vue-的响应规则" class="headerlink" title="Mutation 需遵守 Vue 的响应规则"></a>Mutation 需遵守 Vue 的响应规则</h3><p>既然 Vuex 的 store 中的状态是响应式的，那么当我们变更状态时，监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项：</p><ol><li>最好提前在你的 store 中初始化好所有所需属性。</li><li>当需要在对象上添加新属性时，你应该</li></ol><ul><li><p>使用 <code>Vue.set(obj, &#39;newProp&#39;, 123)</code>, 或者</p></li><li><p>以新对象替换老对象。例如，利用 stage-3 的<a href="https://github.com/sebmarkbage/ecmascript-rest-spread" target="_blank" rel="noopener">对象展开运算符</a>我们可以这样写：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">state.obj = &#123; ...state.obj, <span class="hljs-attr">newProp</span>: <span class="hljs-number">123</span> &#125;</span><br></pre></td></tr></table></figure></li></ul><h3 id="使用常量替代-Mutation-事件类型"><a href="#使用常量替代-Mutation-事件类型" class="headerlink" title="使用常量替代 Mutation 事件类型"></a>使用常量替代 Mutation 事件类型</h3><p>使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用，同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// mutation-types.js</span></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SOME_MUTATION = <span class="hljs-string">'SOME_MUTATION'</span></span><br><span class="line"><span class="hljs-comment">// store.js</span></span><br><span class="line"><span class="hljs-keyword">import</span> Vuex <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span></span><br><span class="line"><span class="hljs-keyword">import</span> &#123; SOME_MUTATION &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'./mutation-types'</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state: &#123; ... &#125;,</span><br><span class="line">  mutations: &#123;</span><br><span class="line">    <span class="hljs-comment">// 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名</span></span><br><span class="line">    [SOME_MUTATION] (state) &#123;</span><br><span class="line">      <span class="hljs-comment">// mutate state</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>用不用常量取决于你——在需要多人协作的大型项目中，这会很有帮助。但如果你不喜欢，你完全可以不这样做。</p><h3 id="Mutation-必须是同步函数"><a href="#Mutation-必须是同步函数" class="headerlink" title="Mutation 必须是同步函数"></a>Mutation 必须是同步函数</h3><p>一条重要的原则就是要记住 <strong>mutation 必须是同步函数</strong>。为什么？请参考下面的例子：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">mutations: &#123;</span><br><span class="line">  someMutation (state) &#123;</span><br><span class="line">    api.callAsyncMethod(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> &#123;</span><br><span class="line">      state.count++</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>现在想象，我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录，devtools 都需要捕捉到前一状态和后一状态的快照。然而，在上面的例子中 mutation 中的异步函数中的回调让这不可能完成：因为当 mutation 触发的时候，回调函数还没有被调用，devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。</p><h3 id="在组件中提交-Mutation"><a href="#在组件中提交-Mutation" class="headerlink" title="在组件中提交 Mutation"></a>在组件中提交 Mutation</h3><p>你可以在组件中使用 <code>this.$store.commit(&#39;xxx&#39;)</code> 提交 mutation，或者使用 <code>mapMutations</code> 辅助函数将组件中的 methods 映射为 <code>store.commit</code> 调用（需要在根节点注入 <code>store</code>）。</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">import</span> &#123; mapMutations &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  methods: &#123;</span><br><span class="line">    ...mapMutations([</span><br><span class="line">      <span class="hljs-string">'increment'</span>, <span class="hljs-comment">// 将 `this.increment()` 映射为 `this.$store.commit('increment')`</span></span><br><span class="line"></span><br><span class="line">      <span class="hljs-comment">// `mapMutations` 也支持载荷：</span></span><br><span class="line">      <span class="hljs-string">'incrementBy'</span> <span class="hljs-comment">// 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`</span></span><br><span class="line">    ]),</span><br><span class="line">    ...mapMutations(&#123;</span><br><span class="line">      add: <span class="hljs-string">'increment'</span> <span class="hljs-comment">// 将 `this.add()` 映射为 `this.$store.commit('increment')`</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Actions-—-动作"><a href="#Actions-—-动作" class="headerlink" title="Actions — 动作"></a>Actions — 动作</h2><p>Action 类似于 mutation，不同在于：</p><ul><li>Action 提交的是 mutation，而不是直接变更状态。</li><li>Action 可以包含任意异步操作。</li></ul><p>让我们来注册一个简单的 action：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state: &#123;</span><br><span class="line">    count: <span class="hljs-number">0</span></span><br><span class="line">  &#125;,</span><br><span class="line">  mutations: &#123;</span><br><span class="line">    increment (state) &#123;</span><br><span class="line">      state.count++</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  actions: &#123;</span><br><span class="line">    increment (context) &#123;</span><br><span class="line">      context.commit(<span class="hljs-string">'increment'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象，因此你可以调用 <code>context.commit</code> 提交一个 mutation，或者通过 <code>context.state</code> 和 <code>context.getters</code> 来获取 state 和 getters。当我们在之后介绍到 <a href="https://vuex.vuejs.org/zh/guide/modules.html" target="_blank" rel="noopener">Modules</a> 时，你就知道 context 对象为什么不是 store 实例本身了。</p><p>实践中，我们会经常用到 ES2015 的 <a href="https://github.com/lukehoban/es6features#destructuring" target="_blank" rel="noopener">参数解构</a> 来简化代码（特别是我们需要调用 <code>commit</code> 很多次的时候）：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">actions: &#123;</span><br><span class="line">  increment (&#123; commit &#125;) &#123;</span><br><span class="line">    commit(<span class="hljs-string">'increment'</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="分发-Action"><a href="#分发-Action" class="headerlink" title="分发 Action"></a>分发 Action</h3><p>Action 通过 <code>store.dispatch</code> 方法触发：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">store.dispatch(<span class="hljs-string">'increment'</span>)</span><br></pre></td></tr></table></figure><p>乍一眼看上去感觉多此一举，我们直接分发 mutation 岂不更方便？实际上并非如此，还记得 <strong>mutation 必须同步执行</strong>这个限制么？Action 就不受约束！我们可以在 action 内部执行<strong>异步</strong>操作：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">actions: &#123;</span><br><span class="line">  incrementAsync (&#123; commit &#125;) &#123;</span><br><span class="line">    setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> &#123;</span><br><span class="line">      commit(<span class="hljs-string">'increment'</span>)</span><br><span class="line">    &#125;, <span class="hljs-number">1000</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Actions 支持同样的载荷方式和对象方式进行分发：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// 以载荷形式分发</span></span><br><span class="line">store.dispatch(<span class="hljs-string">'incrementAsync'</span>, &#123;</span><br><span class="line">  amount: <span class="hljs-number">10</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">// 以对象形式分发</span></span><br><span class="line">store.dispatch(&#123;</span><br><span class="line">  type: <span class="hljs-string">'incrementAsync'</span>,</span><br><span class="line">  amount: <span class="hljs-number">10</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>来看一个更加实际的购物车示例，涉及到<strong>调用异步 API</strong> 和<strong>分发多重 mutation</strong>：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">actions: &#123;</span><br><span class="line">  checkout (&#123; commit, state &#125;, products) &#123;</span><br><span class="line">    <span class="hljs-comment">// 把当前购物车的物品备份起来</span></span><br><span class="line">    <span class="hljs-keyword">const</span> savedCartItems = [...state.cart.added]</span><br><span class="line">    <span class="hljs-comment">// 发出结账请求，然后乐观地清空购物车</span></span><br><span class="line">    commit(types.CHECKOUT_REQUEST)</span><br><span class="line">    <span class="hljs-comment">// 购物 API 接受一个成功回调和一个失败回调</span></span><br><span class="line">    shop.buyProducts(</span><br><span class="line">      products,</span><br><span class="line">      <span class="hljs-comment">// 成功操作</span></span><br><span class="line">      () =&gt; commit(types.CHECKOUT_SUCCESS),</span><br><span class="line">      <span class="hljs-comment">// 失败操作</span></span><br><span class="line">      () =&gt; commit(types.CHECKOUT_FAILURE, savedCartItems)</span><br><span class="line">    )</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意我们正在进行一系列的异步操作，并且通过提交 mutation 来记录 action 产生的副作用（即状态变更）。</p><h3 id="在组件中分发-Action"><a href="#在组件中分发-Action" class="headerlink" title="在组件中分发 Action"></a>在组件中分发 Action</h3><p>你在组件中使用 <code>this.$store.dispatch(&#39;xxx&#39;)</code> 分发 action，或者使用 <code>mapActions</code> 辅助函数将组件的 methods 映射为 <code>store.dispatch</code> 调用（需要先在根节点注入 <code>store</code>）：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">import</span> &#123; mapActions &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  methods: &#123;</span><br><span class="line">    ...mapActions([</span><br><span class="line">      <span class="hljs-string">'increment'</span>, <span class="hljs-comment">// 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`</span></span><br><span class="line"></span><br><span class="line">      <span class="hljs-comment">// `mapActions` 也支持载荷：</span></span><br><span class="line">      <span class="hljs-string">'incrementBy'</span> <span class="hljs-comment">// 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`</span></span><br><span class="line">    ]),</span><br><span class="line">    ...mapActions(&#123;</span><br><span class="line">      add: <span class="hljs-string">'increment'</span> <span class="hljs-comment">// 将 `this.add()` 映射为 `this.$store.dispatch('increment')`</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="组合-Action"><a href="#组合-Action" class="headerlink" title="组合 Action"></a>组合 Action</h3><p>Action 通常是异步的，那么如何知道 action 什么时候结束呢？更重要的是，我们如何才能组合多个 action，以处理更加复杂的异步流程？</p><p>首先，你需要明白 <code>store.dispatch</code> 可以处理被触发的 action 的处理函数返回的 Promise，并且 <code>store.dispatch</code> 仍旧返回 Promise：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">actions: &#123;</span><br><span class="line">  actionA (&#123; commit &#125;) &#123;</span><br><span class="line">    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> &#123;</span><br><span class="line">        commit(<span class="hljs-string">'someMutation'</span>)</span><br><span class="line">        resolve()</span><br><span class="line">      &#125;, <span class="hljs-number">1000</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>现在你可以：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">store.dispatch(<span class="hljs-string">'actionA'</span>).then(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>在另外一个 action 中也可以：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">actions: &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  actionB (&#123; dispatch, commit &#125;) &#123;</span><br><span class="line">    <span class="hljs-keyword">return</span> dispatch(<span class="hljs-string">'actionA'</span>).then(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> &#123;</span><br><span class="line">      commit(<span class="hljs-string">'someOtherMutation'</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>最后，如果我们利用 <a href="https://tc39.github.io/ecmascript-asyncawait/" target="_blank" rel="noopener">async / await</a>，我们可以如下组合 action：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// 假设 getData() 和 getOtherData() 返回的是 Promise</span></span><br><span class="line"></span><br><span class="line">actions: &#123;</span><br><span class="line">  <span class="hljs-keyword">async</span> actionA (&#123; commit &#125;) &#123;</span><br><span class="line">    commit(<span class="hljs-string">'gotData'</span>, <span class="hljs-keyword">await</span> getData())</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="hljs-keyword">async</span> actionB (&#123; dispatch, commit &#125;) &#123;</span><br><span class="line">    <span class="hljs-keyword">await</span> dispatch(<span class="hljs-string">'actionA'</span>) <span class="hljs-comment">// 等待 actionA 完成</span></span><br><span class="line">    commit(<span class="hljs-string">'gotOtherData'</span>, <span class="hljs-keyword">await</span> getOtherData())</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>一个 <code>store.dispatch</code> 在不同模块中可以触发多个 action 函数。在这种情况下，只有当所有触发函数完成后，返回的 Promise 才会执行。</p></blockquote><h2 id="Modules-—-模块"><a href="#Modules-—-模块" class="headerlink" title="Modules — 模块"></a>Modules — 模块</h2><p>由于使用单一状态树，应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时，store 对象就有可能变得相当臃肿。</p><p>为了解决以上问题，Vuex 允许我们将 store 分割成<strong>模块（module）</strong>。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> moduleA = &#123;</span><br><span class="line">  state: &#123; ... &#125;,</span><br><span class="line">  mutations: &#123; ... &#125;,</span><br><span class="line">  actions: &#123; ... &#125;,</span><br><span class="line">  getters: &#123; ... &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">const</span> moduleB = &#123;</span><br><span class="line">  state: &#123; ... &#125;,</span><br><span class="line">  mutations: &#123; ... &#125;,</span><br><span class="line">  actions: &#123; ... &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  modules: &#123;</span><br><span class="line">    a: moduleA,</span><br><span class="line">    b: moduleB</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">store.state.a <span class="hljs-comment">// -&gt; moduleA 的状态</span></span><br><span class="line">store.state.b <span class="hljs-comment">// -&gt; moduleB 的状态</span></span><br></pre></td></tr></table></figure><h3 id="模块的局部状态"><a href="#模块的局部状态" class="headerlink" title="模块的局部状态"></a>模块的局部状态</h3><p>对于模块内部的 mutation 和 getter，接收的第一个参数是<strong>模块的局部状态对象</strong>。</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> moduleA = &#123;</span><br><span class="line">  state: &#123; <span class="hljs-attr">count</span>: <span class="hljs-number">0</span> &#125;,</span><br><span class="line">  mutations: &#123;</span><br><span class="line">    increment (state) &#123;</span><br><span class="line">      <span class="hljs-comment">// 这里的 `state` 对象是模块的局部状态</span></span><br><span class="line">      state.count++</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  getters: &#123;</span><br><span class="line">    doubleCount (state) &#123;</span><br><span class="line">      <span class="hljs-keyword">return</span> state.count * <span class="hljs-number">2</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>同样，对于模块内部的 action，局部状态通过 <code>context.state</code> 暴露出来，根节点状态则为 <code>context.rootState</code>：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> moduleA = &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  actions: &#123;</span><br><span class="line">    incrementIfOddOnRootSum (&#123; state, commit, rootState &#125;) &#123;</span><br><span class="line">      <span class="hljs-keyword">if</span> ((state.count + rootState.count) % <span class="hljs-number">2</span> === <span class="hljs-number">1</span>) &#123;</span><br><span class="line">        commit(<span class="hljs-string">'increment'</span>)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>对于模块内部的 getter，根节点状态会作为第三个参数暴露出来：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> moduleA = &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  getters: &#123;</span><br><span class="line">    sumWithRootCount (state, getters, rootState) &#123;</span><br><span class="line">      <span class="hljs-keyword">return</span> state.count + rootState.count</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="命名空间"><a href="#命名空间" class="headerlink" title="命名空间"></a>命名空间</h3><p>默认情况下，模块内部的 action、mutation 和 getter 是注册在<strong>全局命名空间</strong>的——这样使得多个模块能够对同一 mutation 或 action 作出响应。</p><p>如果希望你的模块具有更高的封装度和复用性，你可以通过添加 <code>namespaced: true</code> 的方式使其成为带命名空间的模块。当模块被注册后，它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  modules: &#123;</span><br><span class="line">    account: &#123;</span><br><span class="line">      namespaced: <span class="hljs-literal">true</span>,</span><br><span class="line"></span><br><span class="line">      <span class="hljs-comment">// 模块内容（module assets）</span></span><br><span class="line">      state: &#123; ... &#125;, <span class="hljs-comment">// 模块内的状态已经是嵌套的了，使用 `namespaced` 属性不会对其产生影响</span></span><br><span class="line">      getters: &#123;</span><br><span class="line">        isAdmin () &#123; ... &#125; <span class="hljs-comment">// -&gt; getters['account/isAdmin']</span></span><br><span class="line">      &#125;,</span><br><span class="line">      actions: &#123;</span><br><span class="line">        login () &#123; ... &#125; <span class="hljs-comment">// -&gt; dispatch('account/login')</span></span><br><span class="line">      &#125;,</span><br><span class="line">      mutations: &#123;</span><br><span class="line">        login () &#123; ... &#125; <span class="hljs-comment">// -&gt; commit('account/login')</span></span><br><span class="line">      &#125;,</span><br><span class="line"></span><br><span class="line">      <span class="hljs-comment">// 嵌套模块</span></span><br><span class="line">      modules: &#123;</span><br><span class="line">        <span class="hljs-comment">// 继承父模块的命名空间</span></span><br><span class="line">        myPage: &#123;</span><br><span class="line">          state: &#123; ... &#125;,</span><br><span class="line">          getters: &#123;</span><br><span class="line">            profile () &#123; ... &#125; <span class="hljs-comment">// -&gt; getters['account/profile']</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;,</span><br><span class="line"></span><br><span class="line">        <span class="hljs-comment">// 进一步嵌套命名空间</span></span><br><span class="line">        posts: &#123;</span><br><span class="line">          namespaced: <span class="hljs-literal">true</span>,</span><br><span class="line"></span><br><span class="line">          state: &#123; ... &#125;,</span><br><span class="line">          getters: &#123;</span><br><span class="line">            popular () &#123; ... &#125; <span class="hljs-comment">// -&gt; getters['account/posts/popular']</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>启用了命名空间的 getter 和 action 会收到局部化的 <code>getter</code>，<code>dispatch</code> 和 <code>commit</code>。换言之，你在使用模块内容（module assets）时不需要在同一模块内额外添加空间名前缀。更改 <code>namespaced</code> 属性后不需要修改模块内的代码。</p><h4 id="在带命名空间的模块内访问全局内容（Global-Assets）"><a href="#在带命名空间的模块内访问全局内容（Global-Assets）" class="headerlink" title="在带命名空间的模块内访问全局内容（Global Assets）"></a>在带命名空间的模块内访问全局内容（Global Assets）</h4><p>如果你希望使用全局 state 和 getter，<code>rootState</code> 和 <code>rootGetter</code> 会作为第三和第四参数传入 getter，也会通过 <code>context</code> 对象的属性传入 action。</p><p>若需要在全局命名空间内分发 action 或提交 mutation，将 <code>{ root: true }</code> 作为第三参数传给 <code>dispatch</code> 或 <code>commit</code> 即可。</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">modules: &#123;</span><br><span class="line">  foo: &#123;</span><br><span class="line">    namespaced: <span class="hljs-literal">true</span>,</span><br><span class="line"></span><br><span class="line">    getters: &#123;</span><br><span class="line">      <span class="hljs-comment">// 在这个模块的 getter 中，`getters` 被局部化了</span></span><br><span class="line">      <span class="hljs-comment">// 你可以使用 getter 的第四个参数来调用 `rootGetters`</span></span><br><span class="line">      someGetter (state, getters, rootState, rootGetters) &#123;</span><br><span class="line">        getters.someOtherGetter <span class="hljs-comment">// -&gt; 'foo/someOtherGetter'</span></span><br><span class="line">        rootGetters.someOtherGetter <span class="hljs-comment">// -&gt; 'someOtherGetter'</span></span><br><span class="line">      &#125;,</span><br><span class="line">      someOtherGetter: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> &#123; ... &#125;</span><br><span class="line">    &#125;,</span><br><span class="line"></span><br><span class="line">    actions: &#123;</span><br><span class="line">      <span class="hljs-comment">// 在这个模块中， dispatch 和 commit 也被局部化了</span></span><br><span class="line">      <span class="hljs-comment">// 他们可以接受 `root` 属性以访问根 dispatch 或 commit</span></span><br><span class="line">      someAction (&#123; dispatch, commit, getters, rootGetters &#125;) &#123;</span><br><span class="line">        getters.someGetter <span class="hljs-comment">// -&gt; 'foo/someGetter'</span></span><br><span class="line">        rootGetters.someGetter <span class="hljs-comment">// -&gt; 'someGetter'</span></span><br><span class="line"></span><br><span class="line">        dispatch(<span class="hljs-string">'someOtherAction'</span>) <span class="hljs-comment">// -&gt; 'foo/someOtherAction'</span></span><br><span class="line">        dispatch(<span class="hljs-string">'someOtherAction'</span>, <span class="hljs-literal">null</span>, &#123; <span class="hljs-attr">root</span>: <span class="hljs-literal">true</span> &#125;) <span class="hljs-comment">// -&gt; 'someOtherAction'</span></span><br><span class="line"></span><br><span class="line">        commit(<span class="hljs-string">'someMutation'</span>) <span class="hljs-comment">// -&gt; 'foo/someMutation'</span></span><br><span class="line">        commit(<span class="hljs-string">'someMutation'</span>, <span class="hljs-literal">null</span>, &#123; <span class="hljs-attr">root</span>: <span class="hljs-literal">true</span> &#125;) <span class="hljs-comment">// -&gt; 'someMutation'</span></span><br><span class="line">      &#125;,</span><br><span class="line">      someOtherAction (ctx, payload) &#123; ... &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="在带命名空间的模块注册全局-action"><a href="#在带命名空间的模块注册全局-action" class="headerlink" title="在带命名空间的模块注册全局 action"></a>在带命名空间的模块注册全局 action</h4><p>若需要在带命名空间的模块注册全局 action，你可添加 <code>root: true</code>，并将这个 action 的定义放在函数 <code>handler</code> 中。例如：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  actions: &#123;</span><br><span class="line">    someOtherAction (&#123;dispatch&#125;) &#123;</span><br><span class="line">      dispatch(<span class="hljs-string">'someAction'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  modules: &#123;</span><br><span class="line">    foo: &#123;</span><br><span class="line">      namespaced: <span class="hljs-literal">true</span>,</span><br><span class="line"></span><br><span class="line">      actions: &#123;</span><br><span class="line">        someAction: &#123;</span><br><span class="line">          root: <span class="hljs-literal">true</span>,</span><br><span class="line">          handler (namespacedContext, payload) &#123; ... &#125; <span class="hljs-comment">// -&gt; 'someAction'</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="带命名空间的绑定函数"><a href="#带命名空间的绑定函数" class="headerlink" title="带命名空间的绑定函数"></a>带命名空间的绑定函数</h4><p>当使用 <code>mapState</code>, <code>mapGetters</code>, <code>mapActions</code> 和 <code>mapMutations</code> 这些函数来绑定带命名空间的模块时，写起来可能比较繁琐：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">computed: &#123;</span><br><span class="line">  ...mapState(&#123;</span><br><span class="line">    a: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.some.nested.module.a,</span><br><span class="line">    b: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.some.nested.module.b</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;,</span><br><span class="line">methods: &#123;</span><br><span class="line">  ...mapActions([</span><br><span class="line">    <span class="hljs-string">'some/nested/module/foo'</span>, <span class="hljs-comment">// -&gt; this['some/nested/module/foo']()</span></span><br><span class="line">    <span class="hljs-string">'some/nested/module/bar'</span> <span class="hljs-comment">// -&gt; this['some/nested/module/bar']()</span></span><br><span class="line">  ])</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>对于这种情况，你可以将模块的空间名称字符串作为第一个参数传递给上述函数，这样所有绑定都会自动将该模块作为上下文。于是上面的例子可以简化为：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">computed: &#123;</span><br><span class="line">  ...mapState(<span class="hljs-string">'some/nested/module'</span>, &#123;</span><br><span class="line">    a: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.a,</span><br><span class="line">    b: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.b</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;,</span><br><span class="line">methods: &#123;</span><br><span class="line">  ...mapActions(<span class="hljs-string">'some/nested/module'</span>, [</span><br><span class="line">    <span class="hljs-string">'foo'</span>, <span class="hljs-comment">// -&gt; this.foo()</span></span><br><span class="line">    <span class="hljs-string">'bar'</span> <span class="hljs-comment">// -&gt; this.bar()</span></span><br><span class="line">  ])</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>而且，你可以通过使用 <code>createNamespacedHelpers</code> 创建基于某个命名空间辅助函数。它返回一个对象，对象里有新的绑定在给定命名空间值上的组件绑定辅助函数：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">import</span> &#123; createNamespacedHelpers &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">const</span> &#123; mapState, mapActions &#125; = createNamespacedHelpers(<span class="hljs-string">'some/nested/module'</span>)</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> &#123;</span><br><span class="line">  computed: &#123;</span><br><span class="line">    <span class="hljs-comment">// 在 `some/nested/module` 中查找</span></span><br><span class="line">    ...mapState(&#123;</span><br><span class="line">      a: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.a,</span><br><span class="line">      b: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.b</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    <span class="hljs-comment">// 在 `some/nested/module` 中查找</span></span><br><span class="line">    ...mapActions([</span><br><span class="line">      <span class="hljs-string">'foo'</span>,</span><br><span class="line">      <span class="hljs-string">'bar'</span></span><br><span class="line">    ])</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="给插件开发者的注意事项"><a href="#给插件开发者的注意事项" class="headerlink" title="给插件开发者的注意事项"></a>给插件开发者的注意事项</h4><p>如果你开发的<a href="https://vuex.vuejs.org/zh/guide/plugins.html" target="_blank" rel="noopener">插件（Plugin）</a>提供了模块并允许用户将其添加到 Vuex store，可能需要考虑模块的空间名称问题。对于这种情况，你可以通过插件的参数对象来允许用户指定空间名称：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// 通过插件的参数对象得到空间名称</span></span><br><span class="line"><span class="hljs-comment">// 然后返回 Vuex 插件函数</span></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createPlugin</span> (<span class="hljs-params">options = &#123;&#125;</span>) </span>&#123;</span><br><span class="line">  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">store</span>) </span>&#123;</span><br><span class="line">    <span class="hljs-comment">// 把空间名字添加到插件模块的类型（type）中去</span></span><br><span class="line">    <span class="hljs-keyword">const</span> namespace = options.namespace || <span class="hljs-string">''</span></span><br><span class="line">    store.dispatch(namespace + <span class="hljs-string">'pluginAction'</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="模块动态注册"><a href="#模块动态注册" class="headerlink" title="模块动态注册"></a>模块动态注册</h3><p>在 store 创建<strong>之后</strong>，你可以使用 <code>store.registerModule</code> 方法注册模块：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// 注册模块 `myModule`</span></span><br><span class="line">store.registerModule(<span class="hljs-string">'myModule'</span>, &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="hljs-comment">// 注册嵌套模块 `nested/myModule`</span></span><br><span class="line">store.registerModule([<span class="hljs-string">'nested'</span>, <span class="hljs-string">'myModule'</span>], &#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>之后就可以通过 <code>store.state.myModule</code> 和 <code>store.state.nested.myModule</code> 访问模块的状态。</p><p>模块动态注册功能使得其他 Vue 插件可以通过在 store 中附加新模块的方式来使用 Vuex 管理状态。例如，<a href="https://github.com/vuejs/vuex-router-sync" target="_blank" rel="noopener"><code>vuex-router-sync</code></a> 插件就是通过动态注册模块将 vue-router 和 vuex 结合在一起，实现应用的路由状态管理。</p><p>你也可以使用 <code>store.unregisterModule(moduleName)</code> 来动态卸载模块。注意，你不能使用此方法卸载静态模块（即创建 store 时声明的模块）。</p><h4 id="保留-state"><a href="#保留-state" class="headerlink" title="保留 state"></a>保留 state</h4><p>在注册一个新 module 时，你很有可能想保留过去的 state，例如从一个服务端渲染的应用保留 state。你可以通过 <code>preserveState</code> 选项将其归档：<code>store.registerModule(&#39;a&#39;, module, { preserveState: true })</code>。</p><p>当你设置 <code>preserveState: true</code> 时，该模块会被注册，action、mutation 和 getter 会被添加到 store 中，但是 state 不会。这里假设 store 的 state 已经包含了这个 module 的 state 并且你不希望将其覆写。</p><h3 id="模块重用"><a href="#模块重用" class="headerlink" title="模块重用"></a>模块重用</h3><p>有时我们可能需要创建一个模块的多个实例，例如：</p><ul><li>创建多个 store，他们公用同一个模块 (例如当 <code>runInNewContext</code> 选项是 <code>false</code> 或 <code>&#39;once&#39;</code> 时，为了<a href="https://ssr.vuejs.org/en/structure.html#avoid-stateful-singletons" target="_blank" rel="noopener">在服务端渲染中避免有状态的单例</a>)</li><li>在一个 store 中多次注册同一个模块</li></ul><p>如果我们使用一个纯对象来声明模块的状态，那么这个状态对象会通过引用被共享，导致状态对象被修改时 store 或模块间数据互相污染的问题。</p><p>实际上这和 Vue 组件内的 <code>data</code> 是同样的问题。因此解决办法也是相同的——使用一个函数来声明模块状态（仅 2.3.0+ 支持）：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> MyReusableModule = &#123;</span><br><span class="line">  state () &#123;</span><br><span class="line">    <span class="hljs-keyword">return</span> &#123;</span><br><span class="line">      foo: <span class="hljs-string">'bar'</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="hljs-comment">// mutation, action 和 getter 等等...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="项目结构"><a href="#项目结构" class="headerlink" title="项目结构"></a>项目结构</h1><p>Vuex 并不限制你的代码结构。但是，它规定了一些需要遵守的规则：</p><ol><li>应用层级的状态应该集中到单个 store 对象中。</li><li>提交 <strong>mutation</strong> 是更改状态的唯一方法，并且这个过程是同步的。</li><li>异步逻辑都应该封装到 <strong>action</strong> 里面。</li></ol><p>只要你遵守以上规则，如何组织代码随你便。如果你的 store 文件太大，只需将 action、mutation 和 getter 分割到单独的文件。</p><p>对于大型应用，我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例：</p><figure class="highlight bash hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">├── index.html</span><br><span class="line">├── main.js</span><br><span class="line">├── api</span><br><span class="line">│   └── ... <span class="hljs-comment"># 抽取出API请求</span></span><br><span class="line">├── components</span><br><span class="line">│   ├── App.vue</span><br><span class="line">│   └── ...</span><br><span class="line">└── store</span><br><span class="line">    ├── index.js          <span class="hljs-comment"># 我们组装模块并导出 store 的地方</span></span><br><span class="line">    ├── actions.js        <span class="hljs-comment"># 根级别的 action</span></span><br><span class="line">    ├── mutations.js      <span class="hljs-comment"># 根级别的 mutation</span></span><br><span class="line">    └── modules</span><br><span class="line">        ├── cart.js       <span class="hljs-comment"># 购物车模块</span></span><br><span class="line">        └── products.js   <span class="hljs-comment"># 产品模块</span></span><br></pre></td></tr></table></figure><h1 id="插件"><a href="#插件" class="headerlink" title="插件"></a>插件</h1><p>Vuex 的 store 接受 <code>plugins</code> 选项，这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数，它接收 store 作为唯一参数：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> myPlugin = <span class="hljs-function"><span class="hljs-params">store</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="hljs-comment">// 当 store 初始化后调用</span></span><br><span class="line">  store.subscribe(<span class="hljs-function">(<span class="hljs-params">mutation, state</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="hljs-comment">// 每次 mutation 之后调用</span></span><br><span class="line">    <span class="hljs-comment">// mutation 的格式为 &#123; type, payload &#125;</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后像这样使用：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  plugins: [myPlugin]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="在插件内提交-Mutation"><a href="#在插件内提交-Mutation" class="headerlink" title="在插件内提交 Mutation"></a>在插件内提交 Mutation</h3><p>在插件中不允许直接修改状态——类似于组件，只能通过提交 mutation 来触发变化。</p><p>通过提交 mutation，插件可以用来同步数据源到 store。例如，同步 websocket 数据源到 store（下面是个大概例子，实际上 <code>createPlugin</code> 方法可以有更多选项来完成复杂任务）：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createWebSocketPlugin</span> (<span class="hljs-params">socket</span>) </span>&#123;</span><br><span class="line">  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-params">store</span> =&gt;</span> &#123;</span><br><span class="line">    socket.on(<span class="hljs-string">'data'</span>, data =&gt; &#123;</span><br><span class="line">      store.commit(<span class="hljs-string">'receiveData'</span>, data)</span><br><span class="line">    &#125;)</span><br><span class="line">    store.subscribe(<span class="hljs-function"><span class="hljs-params">mutation</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="hljs-keyword">if</span> (mutation.type === <span class="hljs-string">'UPDATE_DATA'</span>) &#123;</span><br><span class="line">        socket.emit(<span class="hljs-string">'update'</span>, mutation.payload)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="hljs-keyword">const</span> plugin = createWebSocketPlugin(socket)</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state,</span><br><span class="line">  mutations,</span><br><span class="line">  plugins: [plugin]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="生成-State-快照"><a href="#生成-State-快照" class="headerlink" title="生成 State 快照"></a>生成 State 快照</h3><p>有时候插件需要获得状态的“快照”，比较改变的前后状态。想要实现这项功能，你需要对状态对象进行深拷贝：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> myPluginWithSnapshot = <span class="hljs-function"><span class="hljs-params">store</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="hljs-keyword">let</span> prevState = _.cloneDeep(store.state)</span><br><span class="line">  store.subscribe(<span class="hljs-function">(<span class="hljs-params">mutation, state</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="hljs-keyword">let</span> nextState = _.cloneDeep(state)</span><br><span class="line"></span><br><span class="line">    <span class="hljs-comment">// 比较 prevState 和 nextState...</span></span><br><span class="line"></span><br><span class="line">    <span class="hljs-comment">// 保存状态，用于下一次 mutation</span></span><br><span class="line">    prevState = nextState</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>生成状态快照的插件应该只在开发阶段使用</strong>，使用 webpack 或 Browserify，让构建工具帮我们处理：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  plugins: process.env.NODE_ENV !== <span class="hljs-string">'production'</span></span><br><span class="line">    ? [myPluginWithSnapshot]</span><br><span class="line">    : []</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>上面插件会默认启用。在发布阶段，你需要使用 webpack 的 <a href="https://webpack.js.org/plugins/define-plugin/" target="_blank" rel="noopener">DefinePlugin</a> 或者是 Browserify 的 <a href="https://github.com/hughsk/envify" target="_blank" rel="noopener">envify</a> 使 <code>process.env.NODE_ENV !== &#39;production&#39;</code> 为 <code>false</code>。</p><h3 id="内置-Logger-插件"><a href="#内置-Logger-插件" class="headerlink" title="内置 Logger 插件"></a>内置 Logger 插件</h3><blockquote><p>如果正在使用 <a href="https://github.com/vuejs/vue-devtools" target="_blank" rel="noopener">vue-devtools</a>，你可能不需要此插件。</p></blockquote><p>Vuex 自带一个日志插件用于一般的调试:</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">import</span> createLogger <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex/dist/logger'</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  plugins: [createLogger()]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p><code>createLogger</code> 函数有几个配置项：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> logger = createLogger(&#123;</span><br><span class="line">  collapsed: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 自动展开记录的 mutation</span></span><br><span class="line">  filter (mutation, stateBefore, stateAfter) &#123;</span><br><span class="line">    <span class="hljs-comment">// 若 mutation 需要被记录，就让它返回 true 即可</span></span><br><span class="line">    <span class="hljs-comment">// 顺便，`mutation` 是个 &#123; type, payload &#125; 对象</span></span><br><span class="line">    <span class="hljs-keyword">return</span> mutation.type !== <span class="hljs-string">"aBlacklistedMutation"</span></span><br><span class="line">  &#125;,</span><br><span class="line">  transformer (state) &#123;</span><br><span class="line">    <span class="hljs-comment">// 在开始记录之前转换状态</span></span><br><span class="line">    <span class="hljs-comment">// 例如，只返回指定的子树</span></span><br><span class="line">    <span class="hljs-keyword">return</span> state.subTree</span><br><span class="line">  &#125;,</span><br><span class="line">  mutationTransformer (mutation) &#123;</span><br><span class="line">    <span class="hljs-comment">// mutation 按照 &#123; type, payload &#125; 格式记录</span></span><br><span class="line">    <span class="hljs-comment">// 我们可以按任意方式格式化</span></span><br><span class="line">    <span class="hljs-keyword">return</span> mutation.type</span><br><span class="line">  &#125;,</span><br><span class="line">  logger: <span class="hljs-built_in">console</span>, <span class="hljs-comment">// 自定义 console 实现，默认为 `console`</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>日志插件还可以直接通过 <code>&lt;script&gt;</code> 标签引入，它会提供全局方法 <code>createVuexLogger</code>。</p><p>要注意，logger 插件会生成状态快照，所以仅在开发环境使用。</p><h1 id="严格模式"><a href="#严格模式" class="headerlink" title="严格模式"></a>严格模式</h1><p>开启严格模式，仅需在创建 store 的时候传入 <code>strict: true</code>：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  strict: <span class="hljs-literal">true</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>在严格模式下，无论何时发生了状态变更且不是由 mutation 函数引起的，将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。</p><h3 id="开发环境与发布环境"><a href="#开发环境与发布环境" class="headerlink" title="开发环境与发布环境"></a>开发环境与发布环境</h3><p><strong>不要在发布环境下启用严格模式</strong>！严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式，以避免性能损失。</p><p>类似于插件，我们可以让构建工具来处理这种情况：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  <span class="hljs-comment">// ...</span></span><br><span class="line">  strict: process.env.NODE_ENV !== <span class="hljs-string">'production'</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h1 id="表单处理"><a href="#表单处理" class="headerlink" title="表单处理"></a>表单处理</h1><p>当在严格模式中使用 Vuex 时，在属于 Vuex 的 state 上使用 <code>v-model</code> 会比较棘手：</p><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"obj.message"</span>&gt;</span></span><br></pre></td></tr></table></figure><p>假设这里的 <code>obj</code> 是在计算属性中返回的一个属于 Vuex store 的对象，在用户输入时，<code>v-model</code> 会试图直接修改 <code>obj.message</code>。在严格模式中，由于这个修改不是在 mutation 函数中执行的, 这里会抛出一个错误。</p><p>用“Vuex 的思维”去解决这个问题的方法是：给 <code>&lt;input&gt;</code> 中绑定 value，然后侦听 <code>input</code> 或者 <code>change</code> 事件，在事件回调中调用 action:</p><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">:value</span>=<span class="hljs-string">"message"</span> @<span class="hljs-attr">input</span>=<span class="hljs-string">"updateMessage"</span>&gt;</span></span><br><span class="line">// ...</span><br><span class="line">computed: &#123;</span><br><span class="line">  ...mapState(&#123;</span><br><span class="line">    message: state =&gt; state.obj.message</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;,</span><br><span class="line">methods: &#123;</span><br><span class="line">  updateMessage (e) &#123;</span><br><span class="line">    this.$store.commit('updateMessage', e.target.value)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>下面是 mutation 函数：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// ...</span></span><br><span class="line">mutations: &#123;</span><br><span class="line">  updateMessage (state, message) &#123;</span><br><span class="line">    state.obj.message = message</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="双向绑定的计算属性"><a href="#双向绑定的计算属性" class="headerlink" title="双向绑定的计算属性"></a>双向绑定的计算属性</h3><p>必须承认，这样做比简单地使用“<code>v-model</code> + 局部状态”要啰嗦得多，并且也损失了一些 <code>v-model</code> 中很有用的特性。另一个方法是使用带有 setter 的双向绑定计算属性：</p><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"message"</span>&gt;</span></span><br><span class="line">// ...</span><br><span class="line">computed: &#123;</span><br><span class="line">  message: &#123;</span><br><span class="line">    get () &#123;</span><br><span class="line">      return this.$store.state.obj.message</span><br><span class="line">    &#125;,</span><br><span class="line">    set (value) &#123;</span><br><span class="line">      this.$store.commit('updateMessage', value)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h1><p><a href="https://scrimba.com/p/pnyzgAP/cPGkpJhq" target="_blank" rel="noopener">在 Scrimba 上尝试这节课</a></p><p>我们主要想针对 Vuex 中的 mutation 和 action 进行单元测试。</p><h3 id="测试-Mutation"><a href="#测试-Mutation" class="headerlink" title="测试 Mutation"></a>测试 Mutation</h3><p>Mutation 很容易被测试，因为它们仅仅是一些完全依赖参数的函数。这里有一个小技巧，如果你在 <code>store.js</code> 文件中定义了 mutation，并且使用 ES2015 模块功能默认输出了 Vuex.Store 的实例，那么你仍然可以给 mutation 取个变量名然后把它输出去：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">const</span> state = &#123; ... &#125;</span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">// `mutations` 作为命名输出对象</span></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> mutations = &#123; ... &#125;</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state,</span><br><span class="line">  mutations</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>下面是用 Mocha + Chai 测试一个 mutation 的例子（实际上你可以用任何你喜欢的测试框架）：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// mutations.js</span></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> mutations = &#123;</span><br><span class="line">  increment: <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.count++</span><br><span class="line">&#125;</span><br><span class="line"><span class="hljs-comment">// mutations.spec.js</span></span><br><span class="line"><span class="hljs-keyword">import</span> &#123; expect &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'chai'</span></span><br><span class="line"><span class="hljs-keyword">import</span> &#123; mutations &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'./store'</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">// 解构 `mutations`</span></span><br><span class="line"><span class="hljs-keyword">const</span> &#123; increment &#125; = mutations</span><br><span class="line"></span><br><span class="line">describe(<span class="hljs-string">'mutations'</span>, () =&gt; &#123;</span><br><span class="line">  it(<span class="hljs-string">'INCREMENT'</span>, () =&gt; &#123;</span><br><span class="line">    <span class="hljs-comment">// 模拟状态</span></span><br><span class="line">    <span class="hljs-keyword">const</span> state = &#123; <span class="hljs-attr">count</span>: <span class="hljs-number">0</span> &#125;</span><br><span class="line">    <span class="hljs-comment">// 应用 mutation</span></span><br><span class="line">    increment(state)</span><br><span class="line">    <span class="hljs-comment">// 断言结果</span></span><br><span class="line">    expect(state.count).to.equal(<span class="hljs-number">1</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="测试-Action"><a href="#测试-Action" class="headerlink" title="测试 Action"></a>测试 Action</h3><p>Action 应对起来略微棘手，因为它们可能需要调用外部的 API。当测试 action 的时候，我们需要增加一个 mocking 服务层——例如，我们可以把 API 调用抽象成服务，然后在测试文件中用 mock 服务回应 API 调用。为了便于解决 mock 依赖，可以用 webpack 和 <a href="https://github.com/plasticine/inject-loader" target="_blank" rel="noopener">inject-loader</a> 打包测试文件。</p><p>下面是一个测试异步 action 的例子：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// actions.js</span></span><br><span class="line"><span class="hljs-keyword">import</span> shop <span class="hljs-keyword">from</span> <span class="hljs-string">'../api/shop'</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAllProducts = <span class="hljs-function">(<span class="hljs-params">&#123; commit &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">  commit(<span class="hljs-string">'REQUEST_PRODUCTS'</span>)</span><br><span class="line">  shop.getProducts(<span class="hljs-function"><span class="hljs-params">products</span> =&gt;</span> &#123;</span><br><span class="line">    commit(<span class="hljs-string">'RECEIVE_PRODUCTS'</span>, products)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="hljs-comment">// actions.spec.js</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">// 使用 require 语法处理内联 loaders。</span></span><br><span class="line"><span class="hljs-comment">// inject-loader 返回一个允许我们注入 mock 依赖的模块工厂</span></span><br><span class="line"><span class="hljs-keyword">import</span> &#123; expect &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'chai'</span></span><br><span class="line"><span class="hljs-keyword">const</span> actionsInjector = <span class="hljs-built_in">require</span>(<span class="hljs-string">'inject-loader!./actions'</span>)</span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">// 使用 mocks 创建模块</span></span><br><span class="line"><span class="hljs-keyword">const</span> actions = actionsInjector(&#123;</span><br><span class="line">  <span class="hljs-string">'../api/shop'</span>: &#123;</span><br><span class="line">    getProducts (cb) &#123;</span><br><span class="line">      setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> &#123;</span><br><span class="line">        cb([ <span class="hljs-comment">/* mocked response */</span> ])</span><br><span class="line">      &#125;, <span class="hljs-number">100</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">// 用指定的 mutations 测试 action 的辅助函数</span></span><br><span class="line"><span class="hljs-keyword">const</span> testAction = <span class="hljs-function">(<span class="hljs-params">action, args, state, expectedMutations, done</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span></span><br><span class="line"></span><br><span class="line">  <span class="hljs-comment">// 模拟提交</span></span><br><span class="line">  <span class="hljs-keyword">const</span> commit = <span class="hljs-function">(<span class="hljs-params">type, payload</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="hljs-keyword">const</span> mutation = expectedMutations[count]</span><br><span class="line"></span><br><span class="line">    <span class="hljs-keyword">try</span> &#123;</span><br><span class="line">      expect(mutation.type).to.equal(type)</span><br><span class="line">      <span class="hljs-keyword">if</span> (payload) &#123;</span><br><span class="line">        expect(mutation.payload).to.deep.equal(payload)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="hljs-keyword">catch</span> (error) &#123;</span><br><span class="line">      done(error)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    count++</span><br><span class="line">    <span class="hljs-keyword">if</span> (count &gt;= expectedMutations.length) &#123;</span><br><span class="line">      done()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="hljs-comment">// 用模拟的 store 和参数调用 action</span></span><br><span class="line">  action(&#123; commit, state &#125;, ...args)</span><br><span class="line"></span><br><span class="line">  <span class="hljs-comment">// 检查是否没有 mutation 被 dispatch</span></span><br><span class="line">  <span class="hljs-keyword">if</span> (expectedMutations.length === <span class="hljs-number">0</span>) &#123;</span><br><span class="line">    expect(count).to.equal(<span class="hljs-number">0</span>)</span><br><span class="line">    done()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">describe(<span class="hljs-string">'actions'</span>, () =&gt; &#123;</span><br><span class="line">  it(<span class="hljs-string">'getAllProducts'</span>, done =&gt; &#123;</span><br><span class="line">    testAction(actions.getAllProducts, [], &#123;&#125;, [</span><br><span class="line">      &#123; <span class="hljs-attr">type</span>: <span class="hljs-string">'REQUEST_PRODUCTS'</span> &#125;,</span><br><span class="line">      &#123; <span class="hljs-attr">type</span>: <span class="hljs-string">'RECEIVE_PRODUCTS'</span>, <span class="hljs-attr">payload</span>: &#123; <span class="hljs-comment">/* mocked response */</span> &#125; &#125;</span><br><span class="line">    ], done)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>如果在测试环境下有可用的 spy (比如通过 <a href="http://sinonjs.org/" target="_blank" rel="noopener">Sinon.JS</a>)，你可以使用它们替换辅助函数 <code>testAction</code>：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">describe(<span class="hljs-string">'actions'</span>, () =&gt; &#123;</span><br><span class="line">  it(<span class="hljs-string">'getAllProducts'</span>, () =&gt; &#123;</span><br><span class="line">    <span class="hljs-keyword">const</span> commit = sinon.spy()</span><br><span class="line">    <span class="hljs-keyword">const</span> state = &#123;&#125;</span><br><span class="line">    </span><br><span class="line">    actions.getAllProducts(&#123; commit, state &#125;)</span><br><span class="line">    </span><br><span class="line">    expect(commit.args).to.deep.equal([</span><br><span class="line">      [<span class="hljs-string">'REQUEST_PRODUCTS'</span>],</span><br><span class="line">      [<span class="hljs-string">'RECEIVE_PRODUCTS'</span>, &#123; <span class="hljs-comment">/* mocked response */</span> &#125;]</span><br><span class="line">    ])</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="测试-Getter"><a href="#测试-Getter" class="headerlink" title="测试 Getter"></a>测试 Getter</h3><p>如果你的 getter 包含很复杂的计算过程，很有必要测试它们。Getter 的测试与 mutation 一样直截了当。</p><p>测试一个 getter 的示例：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// getters.js</span></span><br><span class="line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getters = &#123;</span><br><span class="line">  filteredProducts (state, &#123; filterCategory &#125;) &#123;</span><br><span class="line">    <span class="hljs-keyword">return</span> state.products.filter(<span class="hljs-function"><span class="hljs-params">product</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="hljs-keyword">return</span> product.category === filterCategory</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="hljs-comment">// getters.spec.js</span></span><br><span class="line"><span class="hljs-keyword">import</span> &#123; expect &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'chai'</span></span><br><span class="line"><span class="hljs-keyword">import</span> &#123; getters &#125; <span class="hljs-keyword">from</span> <span class="hljs-string">'./getters'</span></span><br><span class="line"></span><br><span class="line">describe(<span class="hljs-string">'getters'</span>, () =&gt; &#123;</span><br><span class="line">  it(<span class="hljs-string">'filteredProducts'</span>, () =&gt; &#123;</span><br><span class="line">    <span class="hljs-comment">// 模拟状态</span></span><br><span class="line">    <span class="hljs-keyword">const</span> state = &#123;</span><br><span class="line">      products: [</span><br><span class="line">        &#123; <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">'Apple'</span>, <span class="hljs-attr">category</span>: <span class="hljs-string">'fruit'</span> &#125;,</span><br><span class="line">        &#123; <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">'Orange'</span>, <span class="hljs-attr">category</span>: <span class="hljs-string">'fruit'</span> &#125;,</span><br><span class="line">        &#123; <span class="hljs-attr">id</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">'Carrot'</span>, <span class="hljs-attr">category</span>: <span class="hljs-string">'vegetable'</span> &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="hljs-comment">// 模拟 getter</span></span><br><span class="line">    <span class="hljs-keyword">const</span> filterCategory = <span class="hljs-string">'fruit'</span></span><br><span class="line"></span><br><span class="line">    <span class="hljs-comment">// 获取 getter 的结果</span></span><br><span class="line">    <span class="hljs-keyword">const</span> result = getters.filteredProducts(state, &#123; filterCategory &#125;)</span><br><span class="line"></span><br><span class="line">    <span class="hljs-comment">// 断言结果</span></span><br><span class="line">    expect(result).to.deep.equal([</span><br><span class="line">      &#123; <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">'Apple'</span>, <span class="hljs-attr">category</span>: <span class="hljs-string">'fruit'</span> &#125;,</span><br><span class="line">      &#123; <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">'Orange'</span>, <span class="hljs-attr">category</span>: <span class="hljs-string">'fruit'</span> &#125;</span><br><span class="line">    ])</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="执行测试"><a href="#执行测试" class="headerlink" title="执行测试"></a>执行测试</h3><p>如果你的 mutation 和 action 编写正确，经过合理地 mocking 处理之后这些测试应该不依赖任何浏览器 API，因此你可以直接用 webpack 打包这些测试文件然后在 Node 中执行。换种方式，你也可以用 <code>mocha-loader</code> 或 Karma + <code>karma-webpack</code>在真实浏览器环境中进行测试。</p><h4 id="在-Node-中执行测试"><a href="#在-Node-中执行测试" class="headerlink" title="在 Node 中执行测试"></a>在 Node 中执行测试</h4><p>创建以下 webpack 配置（配置好 <a href="https://babeljs.io/docs/usage/babelrc/" target="_blank" rel="noopener"><code>.babelrc</code></a>）:</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// webpack.config.js</span></span><br><span class="line"><span class="hljs-built_in">module</span>.exports = &#123;</span><br><span class="line">  entry: <span class="hljs-string">'./test.js'</span>,</span><br><span class="line">  output: &#123;</span><br><span class="line">    path: __dirname,</span><br><span class="line">    filename: <span class="hljs-string">'test-bundle.js'</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="hljs-built_in">module</span>: &#123;</span><br><span class="line">    loaders: [</span><br><span class="line">      &#123;</span><br><span class="line">        test: <span class="hljs-regexp">/\.js$/</span>,</span><br><span class="line">        loader: <span class="hljs-string">'babel-loader'</span>,</span><br><span class="line">        exclude: <span class="hljs-regexp">/node_modules/</span></span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后：</p><figure class="highlight bash hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">webpack</span><br><span class="line">mocha <span class="hljs-built_in">test</span>-bundle.js</span><br></pre></td></tr></table></figure><h4 id="在浏览器中测试"><a href="#在浏览器中测试" class="headerlink" title="在浏览器中测试"></a>在浏览器中测试</h4><ol><li>安装 <code>mocha-loader</code>。</li><li>把上述 webpack 配置中的 <code>entry</code> 改成 <code>&#39;mocha-loader!babel-loader!./test.js&#39;</code>。</li><li>用以上配置启动 <code>webpack-dev-server</code>。</li><li>访问 <code>localhost:8080/webpack-dev-server/test-bundle</code>。</li></ol><h1 id="热重载"><a href="#热重载" class="headerlink" title="热重载"></a>热重载</h1><p>使用 webpack 的 <a href="https://webpack.js.org/guides/hot-module-replacement/" target="_blank" rel="noopener">Hot Module Replacement API</a>，Vuex 支持在开发过程中热重载 mutation、module、action 和 getter。你也可以在 Browserify 中使用 <a href="https://github.com/AgentME/browserify-hmr/" target="_blank" rel="noopener">browserify-hmr</a> 插件。</p><p>对于 mutation 和模块，你需要使用 <code>store.hotUpdate()</code> 方法：</p><figure class="highlight js hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">// store.js</span></span><br><span class="line"><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span></span><br><span class="line"><span class="hljs-keyword">import</span> Vuex <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span></span><br><span class="line"><span class="hljs-keyword">import</span> mutations <span class="hljs-keyword">from</span> <span class="hljs-string">'./mutations'</span></span><br><span class="line"><span class="hljs-keyword">import</span> moduleA <span class="hljs-keyword">from</span> <span class="hljs-string">'./modules/a'</span></span><br><span class="line"></span><br><span class="line">Vue.use(Vuex)</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">const</span> state = &#123; ... &#125;</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">const</span> store = <span class="hljs-keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state,</span><br><span class="line">  mutations,</span><br><span class="line">  modules: &#123;</span><br><span class="line">    a: moduleA</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">if</span> (<span class="hljs-built_in">module</span>.hot) &#123;</span><br><span class="line">  <span class="hljs-comment">// 使 action 和 mutation 成为可热重载模块</span></span><br><span class="line">  <span class="hljs-built_in">module</span>.hot.accept([<span class="hljs-string">'./mutations'</span>, <span class="hljs-string">'./modules/a'</span>], () =&gt; &#123;</span><br><span class="line">    <span class="hljs-comment">// 获取更新后的模块</span></span><br><span class="line">    <span class="hljs-comment">// 因为 babel 6 的模块编译格式问题，这里需要加上 `.default`</span></span><br><span class="line">    <span class="hljs-keyword">const</span> newMutations = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./mutations'</span>).default</span><br><span class="line">    <span class="hljs-keyword">const</span> newModuleA = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./modules/a'</span>).default</span><br><span class="line">    <span class="hljs-comment">// 加载新模块</span></span><br><span class="line">    store.hotUpdate(&#123;</span><br><span class="line">      mutations: newMutations,</span><br><span class="line">      modules: &#123;</span><br><span class="line">        a: newModuleA</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><div><h1>推荐文章<span style="font-size:.45em;color:gray">（由<a href="https://github.com/huiwang/hexo-recommended-posts" target="_blank" rel="noopener">hexo文章推荐插件</a>驱动）</span></h1><ul><li><a href="http://www.borgor.cn/2019-07-25/789de642.html">在Vue-Router中使用跳转动画</a></li><li><a href="http://www.borgor.cn/2019-06-25/cbd6d728.html">使用vue+v-chart制作一个漂亮的饼状图</a></li><li><a href="http://www.borgor.cn/2019-06-14/92f6ccbc.html">Vue-SSR(Server-Side-Renderer)服务器端渲染指南</a></li></ul></div><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/kity@2.0.4/dist/kity.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/kityminder-core@1.4.50/dist/kityminder.core.min.js"></script><script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/hexo-simple-mindmap@0.2.0/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/hexo-simple-mindmap@0.2.0/dist/mindmap.min.css"></div><div class="level is-size-7 is-uppercase"><div class="level-start"><div class="level-item"><span class="is-size-6 has-text-grey has-mr-7">#</span> <a class="has-link-grey -link" href="/tags/Vue/" rel="tag">Vue</a>, <a class="has-link-grey -link" href="/tags/Vuex/" rel="tag">Vuex</a></div></div></div></div></div><div class="card"><div class="card-content"><h3 class="menu-label has-text-centered">喜欢这篇文章？打赏一下作者吧</h3><div class="buttons is-centered"><a class="button is-info donate"><span class="icon is-small"><i class="fab fa-alipay"></i> </span><span>支付宝</span><div class="qrcode"><img src="https://imgs.borgor.cn/imgs20190628231540.png" alt="支付宝"></div></a><a class="button is-success donate"><span class="icon is-small"><i class="fab fa-weixin"></i> </span><span>微信</span><div class="qrcode"><img src="https://imgs.borgor.cn/imgs20190628231554.png" alt="微信"></div></a></div></div></div><div class="card card-transparent"><div class="level post-navigation is-flex-wrap is-mobile"><div class="level-start"><a class="level level-item has-link-grey article-nav-prev" href="/2019-06-11/168aa3b1.html"><i class="level-item fas fa-chevron-left"></i> <span class="level-item">使用Django+Vue.js快速构建项目</span></a></div><div class="level-end"><a class="level level-item has-link-grey article-nav-next" href="/2019-06-10/33f3a505.html"><span class="level-item">Vue组件-Component解析</span> <i class="level-item fas fa-chevron-right"></i></a></div></div></div><div class="card"><div class="card-content"><h3 class="title is-5 has-text-weight-normal">评论</h3><div id="valine-thread" class="content"></div><script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script><script src="//unpkg.com/valine/dist/Valine.min.js"></script><script>new Valine({el:"#valine-thread",notify:!1,verify:!1,app_id:"ybhyfHG9S4TQhIvstdj5pprw-gzGzoHsz",app_key:"ob8A13IBceQXqd8g92nUgNMx",placeholder:"你有想说的么？"})</script></div></div></div><div class="column is-4-tablet is-3-desktop is-3-widescreen has-order-1 column-left"><div class="card widget"><div class="card-content"><nav class="level"><div class="level-item has-text-centered"><div><figure class="image is-128x128 has-mb-6"><img class="is-rounded" src="https://imgs.borgor.cn/imgs20190625111723.jpg" alt="BorGor"></figure><p class="is-size-4 is-block">BorGor</p><p class="is-size-6 is-block">Note?Note!</p><p class="is-size-6 is-flex is-flex-center has-text-grey"><i class="fas fa-map-marker-alt has-mr-7"></i> <span>Lanzhou.Gansu</span></p></div></div></nav><nav class="level is-mobile"><div class="level-item has-text-centered is-marginless"><div><p class="heading">文章</p><p class="title has-text-weight-normal">86</p></div></div><div class="level-item has-text-centered is-marginless"><div><p class="heading">分类</p><p class="title has-text-weight-normal">26</p></div></div><div class="level-item has-text-centered is-marginless"><div><p class="heading">标签</p><p class="title has-text-weight-normal">153</p></div></div></nav><div class="level"><a class="level-item button is-link is-rounded" href="/" target="_blank">关注我</a></div><div class="level is-mobile"><a class="level-item button is-white is-marginless" target="_blank" title="Github" href="https://github.com/cyrusky"><i class="fab fa-github"></i></a></div></div></div><div class="card widget" id="toc"><div class="card-content"><div class="menu"><h3 class="menu-label">目录</h3><ul class="menu-list"><li><a class="is-flex" href="#什么是Vuex"><span class="has-mr-6">1</span> <span>什么是Vuex</span></a></li><li><a class="is-flex" href="#Vuex的安装"><span class="has-mr-6">2</span> <span>Vuex的安装</span></a><ul class="menu-list"><li><a class="is-flex" href="#Direct-Download-CDN"><span class="has-mr-6">2.1</span> <span>Direct Download / CDN</span></a></li><li><a class="is-flex" href="#NPM"><span class="has-mr-6">2.2</span> <span>NPM</span></a></li><li><a class="is-flex" href="#Yarn"><span class="has-mr-6">2.3</span> <span>Yarn</span></a></li></ul></li><li><a class="is-flex" href="#Vuex的基础概念"><span class="has-mr-6">3</span> <span>Vuex的基础概念</span></a><ul class="menu-list"><li><a class="is-flex" href="#State-—-状态"><span class="has-mr-6">3.1</span> <span>State — 状态</span></a><ul class="menu-list"><li><a class="is-flex" href="#在-Vue-组件中获得-Vuex-状态"><span class="has-mr-6">3.1.1</span> <span>在 Vue 组件中获得 Vuex 状态</span></a></li><li><a class="is-flex" href="#mapState-辅助函数"><span class="has-mr-6">3.1.2</span> <span>mapState 辅助函数</span></a></li><li><a class="is-flex" href="#对象展开运算符"><span class="has-mr-6">3.1.3</span> <span>对象展开运算符</span></a></li><li><a class="is-flex" href="#组件仍然保有局部状态"><span class="has-mr-6">3.1.4</span> <span>组件仍然保有局部状态</span></a></li></ul></li><li><a class="is-flex" href="#Getters-—-获取器"><span class="has-mr-6">3.2</span> <span>Getters — 获取器</span></a><ul class="menu-list"><li><a class="is-flex" href="#通过属性访问"><span class="has-mr-6">3.2.1</span> <span>通过属性访问</span></a></li><li><a class="is-flex" href="#通过方法访问"><span class="has-mr-6">3.2.2</span> <span>通过方法访问</span></a></li><li><a class="is-flex" href="#mapGetters-辅助函数"><span class="has-mr-6">3.2.3</span> <span>mapGetters 辅助函数</span></a></li></ul></li><li><a class="is-flex" href="#Mutations-—-修改器"><span class="has-mr-6">3.3</span> <span>Mutations — 修改器</span></a><ul class="menu-list"><li><a class="is-flex" href="#提交载荷（Payload）"><span class="has-mr-6">3.3.1</span> <span>提交载荷（Payload）</span></a></li><li><a class="is-flex" href="#对象风格的提交方式"><span class="has-mr-6">3.3.2</span> <span>对象风格的提交方式</span></a></li><li><a class="is-flex" href="#Mutation-需遵守-Vue-的响应规则"><span class="has-mr-6">3.3.3</span> <span>Mutation 需遵守 Vue 的响应规则</span></a></li><li><a class="is-flex" href="#使用常量替代-Mutation-事件类型"><span class="has-mr-6">3.3.4</span> <span>使用常量替代 Mutation 事件类型</span></a></li><li><a class="is-flex" href="#Mutation-必须是同步函数"><span class="has-mr-6">3.3.5</span> <span>Mutation 必须是同步函数</span></a></li><li><a class="is-flex" href="#在组件中提交-Mutation"><span class="has-mr-6">3.3.6</span> <span>在组件中提交 Mutation</span></a></li></ul></li><li><a class="is-flex" href="#Actions-—-动作"><span class="has-mr-6">3.4</span> <span>Actions — 动作</span></a><ul class="menu-list"><li><a class="is-flex" href="#分发-Action"><span class="has-mr-6">3.4.1</span> <span>分发 Action</span></a></li><li><a class="is-flex" href="#在组件中分发-Action"><span class="has-mr-6">3.4.2</span> <span>在组件中分发 Action</span></a></li><li><a class="is-flex" href="#组合-Action"><span class="has-mr-6">3.4.3</span> <span>组合 Action</span></a></li></ul></li><li><a class="is-flex" href="#Modules-—-模块"><span class="has-mr-6">3.5</span> <span>Modules — 模块</span></a><ul class="menu-list"><li><a class="is-flex" href="#模块的局部状态"><span class="has-mr-6">3.5.1</span> <span>模块的局部状态</span></a></li><li><a class="is-flex" href="#命名空间"><span class="has-mr-6">3.5.2</span> <span>命名空间</span></a></li><li><a class="is-flex" href="#模块动态注册"><span class="has-mr-6">3.5.3</span> <span>模块动态注册</span></a></li><li><a class="is-flex" href="#模块重用"><span class="has-mr-6">3.5.4</span> <span>模块重用</span></a></li></ul></li></ul></li><li><a class="is-flex" href="#项目结构"><span class="has-mr-6">4</span> <span>项目结构</span></a></li><li><a class="is-flex" href="#插件"><span class="has-mr-6">5</span> <span>插件</span></a><ul class="menu-list"><ul class="menu-list"><li><a class="is-flex" href="#在插件内提交-Mutation"><span class="has-mr-6">5.1.1</span> <span>在插件内提交 Mutation</span></a></li><li><a class="is-flex" href="#生成-State-快照"><span class="has-mr-6">5.1.2</span> <span>生成 State 快照</span></a></li><li><a class="is-flex" href="#内置-Logger-插件"><span class="has-mr-6">5.1.3</span> <span>内置 Logger 插件</span></a></li></ul></ul></li><li><a class="is-flex" href="#严格模式"><span class="has-mr-6">6</span> <span>严格模式</span></a><ul class="menu-list"><ul class="menu-list"><li><a class="is-flex" href="#开发环境与发布环境"><span class="has-mr-6">6.1.1</span> <span>开发环境与发布环境</span></a></li></ul></ul></li><li><a class="is-flex" href="#表单处理"><span class="has-mr-6">7</span> <span>表单处理</span></a><ul class="menu-list"><ul class="menu-list"><li><a class="is-flex" href="#双向绑定的计算属性"><span class="has-mr-6">7.1.1</span> <span>双向绑定的计算属性</span></a></li></ul></ul></li><li><a class="is-flex" href="#测试"><span class="has-mr-6">8</span> <span>测试</span></a><ul class="menu-list"><ul class="menu-list"><li><a class="is-flex" href="#测试-Mutation"><span class="has-mr-6">8.1.1</span> <span>测试 Mutation</span></a></li><li><a class="is-flex" href="#测试-Action"><span class="has-mr-6">8.1.2</span> <span>测试 Action</span></a></li><li><a class="is-flex" href="#测试-Getter"><span class="has-mr-6">8.1.3</span> <span>测试 Getter</span></a></li><li><a class="is-flex" href="#执行测试"><span class="has-mr-6">8.1.4</span> <span>执行测试</span></a></li></ul></ul></li><li><a class="is-flex" href="#热重载"><span class="has-mr-6">9</span> <span>热重载</span></a></li><li><a class="is-flex" href="#undefined"><span class="has-mr-6">10</span> <span>推荐文章（由hexo文章推荐插件驱动）</span></a></li></ul></div></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">分类</h3><ul class="menu-list"><li><a class="level is-marginless" href="/categories/AI/"><span class="level-start"><span class="level-item">AI</span> </span><span class="level-end"><span class="level-item tag">20</span></span></a><ul><li><a class="level is-marginless" href="/categories/AI/Machine-Learning/"><span class="level-start"><span class="level-item">Machine Learning</span> </span><span class="level-end"><span class="level-item tag">6</span></span></a></li><li><a class="level is-marginless" href="/categories/AI/Mathematics/"><span class="level-start"><span class="level-item">Mathematics</span> </span><span class="level-end"><span class="level-item tag">9</span></span></a></li><li><a class="level is-marginless" href="/categories/AI/NLP/"><span class="level-start"><span class="level-item">NLP</span> </span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-marginless" href="/categories/AI/%E5%85%AC%E5%BC%8F%E6%8E%A8%E5%AF%BC/"><span class="level-start"><span class="level-item">公式推导</span> </span><span class="level-end"><span class="level-item tag">4</span></span></a></li></ul></li><li><a class="level is-marginless" href="/categories/CheatSheets/"><span class="level-start"><span class="level-item">CheatSheets</span> </span><span class="level-end"><span class="level-item tag">4</span></span></a></li><li><a class="level is-marginless" href="/categories/DevOps/"><span class="level-start"><span class="level-item">DevOps</span> </span><span class="level-end"><span class="level-item tag">8</span></span></a><ul><li><a class="level is-marginless" href="/categories/DevOps/Anti-patterns/"><span class="level-start"><span class="level-item">Anti-patterns</span> </span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-marginless" href="/categories/DevOps/Concept/"><span class="level-start"><span class="level-item">Concept</span> </span><span class="level-end"><span class="level-item tag">3</span></span></a></li><li><a class="level is-marginless" href="/categories/DevOps/Continuous-Delivery/"><span class="level-start"><span class="level-item">Continuous Delivery</span> </span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-marginless" href="/categories/DevOps/TeamWorks/"><span class="level-start"><span class="level-item">TeamWorks</span> </span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-marginless" href="/categories/DevOps/Testing/"><span class="level-start"><span class="level-item">Testing</span> </span><span class="level-end"><span class="level-item tag">1</span></span></a></li></ul></li><li><a class="level is-marginless" href="/categories/Development/"><span class="level-start"><span class="level-item">Development</span> </span><span class="level-end"><span class="level-item tag">33</span></span></a><ul><li><a class="level is-marginless" href="/categories/Development/Integrated/"><span class="level-start"><span class="level-item">Integrated</span> </span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-marginless" href="/categories/Development/JavaScript/"><span class="level-start"><span class="level-item">JavaScript</span> </span><span class="level-end"><span class="level-item tag">18</span></span></a></li><li><a class="level is-marginless" href="/categories/Development/Native/"><span class="level-start"><span class="level-item">Native</span> </span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-marginless" href="/categories/Development/Python/"><span class="level-start"><span class="level-item">Python</span> </span><span class="level-end"><span class="level-item tag">9</span></span></a></li><li><a class="level is-marginless" href="/categories/Development/React/"><span class="level-start"><span class="level-item">React</span> </span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-marginless" href="/categories/Development/html5/"><span class="level-start"><span class="level-item">html5</span> </span><span class="level-end"><span class="level-item tag">1</span></span></a></li></ul></li><li><a class="level is-marginless" href="/categories/Operations/"><span class="level-start"><span class="level-item">Operations</span> </span><span class="level-end"><span class="level-item tag">18</span></span></a><ul><li><a class="level is-marginless" href="/categories/Operations/Nginx/"><span class="level-start"><span class="level-item">Nginx</span> </span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-marginless" href="/categories/Operations/OpenStack/"><span class="level-start"><span class="level-item">OpenStack</span> </span><span class="level-end"><span class="level-item tag">14</span></span></a></li><li><a class="level is-marginless" href="/categories/Operations/System/"><span class="level-start"><span class="level-item">System</span> </span><span class="level-end"><span class="level-item tag">3</span></span></a></li></ul></li><li><a class="level is-marginless" href="/categories/Reading-Writing/"><span class="level-start"><span class="level-item">Reading&Writing</span> </span><span class="level-end"><span class="level-item tag">3</span></span></a><ul><li><a class="level is-marginless" href="/categories/Reading-Writing/Hexo/"><span class="level-start"><span class="level-item">Hexo</span> </span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-marginless" href="/categories/Reading-Writing/LaTeX/"><span class="level-start"><span class="level-item">LaTeX</span> </span><span class="level-end"><span class="level-item tag">1</span></span></a></li></ul></li></ul></div></div></div><div class="card widget"><div class="card-content"><h3 class="menu-label">标签云</h3><a href="/tags/Agile/" style="font-size:10px">Agile</a> <a href="/tags/Angularjs/" style="font-size:11.11px">Angularjs</a> <a href="/tags/Animation/" style="font-size:10px">Animation</a> <a href="/tags/Application/" style="font-size:10px">Application</a> <a href="/tags/Artificial-Intelligence/" style="font-size:10px">Artificial Intelligence</a> <a href="/tags/BP/" style="font-size:10px">BP</a> <a href="/tags/Bokeh/" style="font-size:10px">Bokeh</a> <a href="/tags/Book/" style="font-size:10px">Book</a> <a href="/tags/C4-5/" style="font-size:10px">C4.5</a> <a href="/tags/CART/" style="font-size:10px">CART</a> <a href="/tags/CD/" style="font-size:10px">CD</a> <a href="/tags/CLI/" style="font-size:10px">CLI</a> <a href="/tags/CSS/" style="font-size:10px">CSS</a> <a href="/tags/CentOS/" style="font-size:11.11px">CentOS</a> <a href="/tags/Cinder/" style="font-size:10px">Cinder</a> <a href="/tags/Clipboardjs/" style="font-size:10px">Clipboardjs</a> <a href="/tags/Concept/" style="font-size:10px">Concept</a> <a href="/tags/Continuous-Delivery/" style="font-size:10px">Continuous Delivery</a> <a href="/tags/DeepLearning/" style="font-size:16.67px">DeepLearning</a> <a href="/tags/Department/" style="font-size:11.11px">Department</a> <a href="/tags/DevOps/" style="font-size:17.78px">DevOps</a> <a href="/tags/Develop/" style="font-size:13.33px">Develop</a> <a href="/tags/Development/" style="font-size:20px">Development</a> <a href="/tags/Directive/" style="font-size:10px">Directive</a> <a href="/tags/Distribution/" style="font-size:10px">Distribution</a> <a href="/tags/Django/" style="font-size:12.22px">Django</a> <a href="/tags/Document/" style="font-size:10px">Document</a> <a href="/tags/ES5/" style="font-size:10px">ES5</a> <a href="/tags/ES6/" style="font-size:10px">ES6</a> <a href="/tags/Echarts/" style="font-size:10px">Echarts</a> <a href="/tags/Engine/" style="font-size:10px">Engine</a> <a href="/tags/Entropy/" style="font-size:10px">Entropy</a> <a href="/tags/Filter/" style="font-size:10px">Filter</a> <a href="/tags/Front-End/" style="font-size:10px">Front End</a> <a href="/tags/Gallery/" style="font-size:10px">Gallery</a> <a href="/tags/Git/" style="font-size:10px">Git</a> <a href="/tags/Gradient-descent/" style="font-size:10px">Gradient descent</a> <a href="/tags/Hexo/" style="font-size:12.22px">Hexo</a> <a href="/tags/Horizon/" style="font-size:10px">Horizon</a> <a href="/tags/ID3-5/" style="font-size:10px">ID3.5</a> <a href="/tags/Icarus/" style="font-size:10px">Icarus</a> <a href="/tags/JavaScript/" style="font-size:18.89px">JavaScript</a> <a href="/tags/Javascript/" style="font-size:11.11px">Javascript</a> <a href="/tags/KVM/" style="font-size:10px">KVM</a> <a href="/tags/LaTeX/" style="font-size:10px">LaTeX</a> <a href="/tags/LibreOffice/" style="font-size:10px">LibreOffice</a> <a href="/tags/Linux/" style="font-size:10px">Linux</a> <a href="/tags/Machine-Learning/" style="font-size:11.11px">Machine Learning</a> <a href="/tags/Matrix/" style="font-size:10px">Matrix</a> <a href="/tags/MiddleWare/" style="font-size:10px">MiddleWare</a> <a href="/tags/Module/" style="font-size:10px">Module</a> <a href="/tags/Network/" style="font-size:10px">Network</a> <a href="/tags/Nginx/" style="font-size:10px">Nginx</a> <a href="/tags/NodeJS/" style="font-size:11.11px">NodeJS</a> <a href="/tags/OOP/" style="font-size:10px">OOP</a> <a href="/tags/OpenStack/" style="font-size:17.78px">OpenStack</a> <a href="/tags/OpenStackApi/" style="font-size:14.44px">OpenStackApi</a> <a href="/tags/Operations/" style="font-size:10px">Operations</a> <a href="/tags/Oprations/" style="font-size:11.11px">Oprations</a> <a href="/tags/PDF/" style="font-size:10px">PDF</a> <a href="/tags/Pipline/" style="font-size:10px">Pipline</a> <a href="/tags/Probability/" style="font-size:12.22px">Probability</a> <a href="/tags/Python/" style="font-size:15.56px">Python</a> <a href="/tags/React/" style="font-size:11.11px">React</a> <a href="/tags/Relational-algebra/" style="font-size:10px">Relational algebra</a> <a href="/tags/Restful/" style="font-size:10px">Restful</a> <a href="/tags/Route/" style="font-size:10px">Route</a> <a href="/tags/SVD/" style="font-size:10px">SVD</a> <a href="/tags/SVM/" style="font-size:11.11px">SVM</a> <a href="/tags/Scalar/" style="font-size:10px">Scalar</a> <a href="/tags/Sigmoid/" style="font-size:10px">Sigmoid</a> <a href="/tags/Team/" style="font-size:10px">Team</a> <a href="/tags/Tempest/" style="font-size:10px">Tempest</a> <a href="/tags/Tensor/" style="font-size:10px">Tensor</a> <a href="/tags/Testing/" style="font-size:10px">Testing</a> <a href="/tags/Time/" style="font-size:10px">Time</a> <a href="/tags/TimeMachine/" style="font-size:10px">TimeMachine</a> <a href="/tags/Tips/" style="font-size:10px">Tips</a> <a href="/tags/Vector/" style="font-size:10px">Vector</a> <a href="/tags/Vmware/" style="font-size:10px">Vmware</a> <a href="/tags/Vue/" style="font-size:17.78px">Vue</a> <a href="/tags/Vuex/" style="font-size:10px">Vuex</a> <a href="/tags/WSGI/" style="font-size:10px">WSGI</a> <a href="/tags/Web/" style="font-size:10px">Web</a> <a href="/tags/Word-Cut/" style="font-size:10px">Word Cut</a> <a href="/tags/aliyun/" style="font-size:10px">aliyun</a> <a href="/tags/auth/" style="font-size:10px">auth</a> <a href="/tags/babel/" style="font-size:10px">babel</a> <a href="/tags/certbot/" style="font-size:10px">certbot</a> <a href="/tags/decision-tree/" style="font-size:10px">decision tree</a> <a href="/tags/homebrew/" style="font-size:10px">homebrew</a> <a href="/tags/jwt/" style="font-size:10px">jwt</a> <a href="/tags/keystone/" style="font-size:11.11px">keystone</a> <a href="/tags/loader/" style="font-size:10px">loader</a> <a href="/tags/mathematics/" style="font-size:11.11px">mathematics</a> <a href="/tags/migrate/" style="font-size:10px">migrate</a> <a href="/tags/openstack/" style="font-size:10px">openstack</a> <a href="/tags/pdf2html/" style="font-size:10px">pdf2html</a> <a href="/tags/pm2/" style="font-size:10px">pm2</a> <a href="/tags/singular-value-decomposition/" style="font-size:10px">singular value decomposition</a> <a href="/tags/vue-router/" style="font-size:11.11px">vue-router</a> <a href="/tags/vue-ssr/" style="font-size:10px">vue-ssr</a> <a href="/tags/webpack/" style="font-size:10px">webpack</a> <a href="/tags/%E4%BD%8E%E9%80%9A%E6%BB%A4%E6%B3%A2%E5%99%A8/" style="font-size:10px">低通滤波器</a> <a href="/tags/%E5%85%A5%E9%97%A8/" style="font-size:10px">入门</a> <a href="/tags/%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F/" style="font-size:10px">全局变量</a> <a href="/tags/%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1/" style="font-size:10px">全局对象</a> <a href="/tags/%E5%85%A8%E6%A0%88/" style="font-size:10px">全栈</a> <a href="/tags/%E5%85%AC%E5%BC%8F/" style="font-size:12.22px">公式</a> <a href="/tags/%E5%86%B3%E7%AD%96%E6%A0%91/" style="font-size:10px">决策树</a> <a href="/tags/%E5%87%BD%E6%95%B0/" style="font-size:10px">函数</a> <a href="/tags/%E5%88%86%E7%B1%BB%E5%99%A8/" style="font-size:10px">分类器</a> <a href="/tags/%E5%8A%A0%E9%80%9F/" style="font-size:10px">加速</a> <a href="/tags/%E5%8C%B9%E9%85%8D%E6%BB%A4%E6%B3%A2%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B/" style="font-size:10px">匹配滤波边缘检测</a> <a href="/tags/%E5%8D%B7%E7%A7%AF/" style="font-size:10px">卷积</a> <a href="/tags/%E5%8D%B7%E7%A7%AF%E6%A0%B8/" style="font-size:10px">卷积核</a> <a href="/tags/%E5%8E%9F%E5%9E%8B%E9%93%BE/" style="font-size:10px">原型链</a> <a href="/tags/%E5%8F%8D%E5%90%91%E4%BC%A0%E6%92%AD/" style="font-size:10px">反向传播</a> <a href="/tags/%E5%8F%98%E9%87%8F%E7%B1%BB%E5%9E%8B/" style="font-size:10px">变量类型</a> <a href="/tags/%E5%AE%98%E6%96%B9%E7%A4%BA%E4%BE%8B/" style="font-size:10px">官方示例</a> <a href="/tags/%E5%AF%B9%E5%81%B6%E5%BD%A2%E5%BC%8F/" style="font-size:10px">对偶形式</a> <a href="/tags/%E5%AF%B9%E8%B1%A1/" style="font-size:10px">对象</a> <a href="/tags/%E5%B9%B3%E7%A7%BB%E5%92%8C%E6%9F%A5%E5%88%86%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B/" style="font-size:10px">平移和查分边缘检测</a> <a href="/tags/%E6%8B%89%E6%A0%BC%E6%9C%97%E6%97%A5%E4%B9%98%E5%AD%90%E6%B3%95/" style="font-size:10px">拉格朗日乘子法</a> <a href="/tags/%E6%8E%A8%E5%AF%BC/" style="font-size:12.22px">推导</a> <a href="/tags/%E6%8F%90%E4%BA%A4%E9%98%B6%E6%AE%B5/" style="font-size:10px">提交阶段</a> <a href="/tags/%E6%9C%80%E5%A4%A7%E4%BC%BC%E7%84%B6%E4%BC%B0%E8%AE%A1/" style="font-size:10px">最大似然估计</a> <a href="/tags/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E4%BC%B0%E8%AE%A1/" style="font-size:10px">最小二乘估计</a> <a href="/tags/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E6%B3%95/" style="font-size:10px">最小二乘法</a> <a href="/tags/%E6%9C%B4%E7%B4%A0%E8%B4%9D%E5%8F%B6%E6%96%AF/" style="font-size:10px">朴素贝叶斯</a> <a href="/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/" style="font-size:10px">机器学习</a> <a href="/tags/%E6%9D%A1%E4%BB%B6%E6%A6%82%E7%8E%87/" style="font-size:10px">条件概率</a> <a href="/tags/%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D/" style="font-size:11.11px">梯度下降</a> <a href="/tags/%E6%A2%AF%E5%BA%A6%E6%96%B9%E5%90%91%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B/" style="font-size:10px">梯度方向边缘检测</a> <a href="/tags/%E6%A6%82%E5%BF%B5/" style="font-size:10px">概念</a> <a href="/tags/%E6%A6%82%E7%8E%87/" style="font-size:10px">概率</a> <a href="/tags/%E6%B1%82%E5%AF%BC/" style="font-size:10px">求导</a> <a href="/tags/%E6%B5%81%E7%A8%8B/" style="font-size:10px">流程</a> <a href="/tags/%E7%86%B5/" style="font-size:10px">熵</a> <a href="/tags/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/" style="font-size:10px">生命周期</a> <a href="/tags/%E7%9F%A9%E9%98%B5/" style="font-size:10px">矩阵</a> <a href="/tags/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/" style="font-size:10px">神经网络</a> <a href="/tags/%E7%A7%81%E6%9C%89%E5%AF%B9%E8%B1%A1/" style="font-size:10px">私有对象</a> <a href="/tags/%E7%B1%BB/" style="font-size:10px">类</a> <a href="/tags/%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/" style="font-size:10px">线性回归</a> <a href="/tags/%E8%81%94%E5%90%88%E6%A6%82%E7%8E%87/" style="font-size:10px">联合概率</a> <a href="/tags/%E8%B4%9D%E5%8F%B6%E6%96%AF%E5%88%A4%E5%AE%9A%E5%87%86%E5%88%99/" style="font-size:10px">贝叶斯判定准则</a> <a href="/tags/%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B/" style="font-size:10px">边缘检测</a> <a href="/tags/%E8%BE%B9%E9%99%85%E6%A6%82%E7%8E%87/" style="font-size:10px">边际概率</a> <a href="/tags/%E9%97%AD%E5%8C%85/" style="font-size:10px">闭包</a> <a href="/tags/%E9%97%B4%E9%9A%94/" style="font-size:11.11px">间隔</a> <a href="/tags/%E9%AB%98%E6%96%AF%E5%88%86%E5%B8%83/" style="font-size:10px">高斯分布</a> <a href="/tags/%E9%AB%98%E9%80%9A%E6%BB%A4%E6%B3%A2%E5%99%A8/" style="font-size:10px">高通滤波器</a></div></div><div class="column-right-shadow"><div class="card widget"><div class="card-content"><h3 class="menu-label">最新文章</h3><article class="media"><a href="/2019-11-24/4adcf99c.html" class="media-left"><p class="image is-64x64"><img class="thumbnail" src="https://imgs.borgor.cn/imgs/20191124220507.png" alt="JavaScript闭包到底解决了什么问题？"></p></a><div class="media-content"><div class="content"><div><time class="has-text-grey is-size-7 is-uppercase" datetime="2019-11-24T12:42:13.000Z">2019-11-24</time></div><a href="/2019-11-24/4adcf99c.html" class="has-link-black-ter is-size-6">JavaScript闭包到底解决了什么问题？</a><p class="is-size-7 is-uppercase"><a class="has-link-grey -link" href="/categories/Development/">Development</a> / <a class="has-link-grey -link" href="/categories/Development/JavaScript/">JavaScript</a></p></div></div></article><article class="media"><a href="/2019-11-22/f971e187.html" class="media-left"><p class="image is-64x64"><img class="thumbnail" src="https://imgs.borgor.cn/imgs/20191122161153.png" alt="JavaScript中对象的生命周期"></p></a><div class="media-content"><div class="content"><div><time class="has-text-grey is-size-7 is-uppercase" datetime="2019-11-22T06:04:32.000Z">2019-11-22</time></div><a href="/2019-11-22/f971e187.html" class="has-link-black-ter is-size-6">JavaScript中对象的生命周期</a><p class="is-size-7 is-uppercase"><a class="has-link-grey -link" href="/categories/Development/">Development</a> / <a class="has-link-grey -link" href="/categories/Development/JavaScript/">JavaScript</a></p></div></div></article><article class="media"><a href="/2019-11-21/c07cc943.html" class="media-left"><p class="image is-64x64"><img class="thumbnail" src="https://imgs.borgor.cn/imgs/20191121175758.png" alt="React官方示例中的小游戏示例"></p></a><div class="media-content"><div class="content"><div><time class="has-text-grey is-size-7 is-uppercase" datetime="2019-11-21T09:56:03.000Z">2019-11-21</time></div><a href="/2019-11-21/c07cc943.html" class="has-link-black-ter is-size-6">React官方示例中的小游戏示例</a><p class="is-size-7 is-uppercase"><a class="has-link-grey -link" href="/categories/Development/">Development</a> / <a class="has-link-grey -link" href="/categories/Development/React/">React</a></p></div></div></article><article class="media"><a href="/2019-11-21/769edcc6.html" class="media-left"><p class="image is-64x64"><img class="thumbnail" src="https://imgs.borgor.cn/imgs/20191121141128.png" alt="JavaScript引擎的工作原理探析"></p></a><div class="media-content"><div class="content"><div><time class="has-text-grey is-size-7 is-uppercase" datetime="2019-11-21T00:30:12.000Z">2019-11-21</time></div><a href="/2019-11-21/769edcc6.html" class="has-link-black-ter is-size-6">JavaScript引擎的工作原理探析</a><p class="is-size-7 is-uppercase"><a class="has-link-grey -link" href="/categories/Development/">Development</a> / <a class="has-link-grey -link" href="/categories/Development/JavaScript/">JavaScript</a></p></div></div></article><article class="media"><a href="/2019-11-19/290f6390.html" class="media-left"><p class="image is-64x64"><img class="thumbnail" src="https://imgs.borgor.cn/imgs/20191119100237.png" alt="深入了解JavaScript中的基本变量类型"></p></a><div class="media-content"><div class="content"><div><time class="has-text-grey is-size-7 is-uppercase" datetime="2019-11-19T04:22:33.000Z">2019-11-19</time></div><a href="/2019-11-19/290f6390.html" class="has-link-black-ter is-size-6">深入了解JavaScript中的基本变量类型</a><p class="is-size-7 is-uppercase"><a class="has-link-grey -link" href="/categories/Development/">Development</a> / <a class="has-link-grey -link" href="/categories/Development/JavaScript/">JavaScript</a></p></div></div></article></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">归档</h3><ul class="menu-list"><li><a class="level is-marginless" href="/archives/2019/11/"><span class="level-start"><span class="level-item">十一月 2019</span> </span><span class="level-end"><span class="level-item tag">7</span></span></a></li><li><a class="level is-marginless" href="/archives/2019/10/"><span class="level-start"><span class="level-item">十月 2019</span> </span><span class="level-end"><span class="level-item tag">8</span></span></a></li><li><a class="level is-marginless" href="/archives/2019/09/"><span class="level-start"><span class="level-item">九月 2019</span> </span><span class="level-end"><span class="level-item tag">5</span></span></a></li><li><a class="level is-marginless" href="/archives/2019/08/"><span class="level-start"><span class="level-item">八月 2019</span> </span><span class="level-end"><span class="level-item tag">13</span></span></a></li><li><a class="level is-marginless" href="/archives/2019/07/"><span class="level-start"><span class="level-item">七月 2019</span> </span><span class="level-end"><span class="level-item tag">15</span></span></a></li><li><a class="level is-marginless" href="/archives/2019/06/"><span class="level-start"><span class="level-item">六月 2019</span> </span><span class="level-end"><span class="level-item tag">11</span></span></a></li><li><a class="level is-marginless" href="/archives/2018/07/"><span class="level-start"><span class="level-item">七月 2018</span> </span><span class="level-end"><span class="level-item tag">4</span></span></a></li><li><a class="level is-marginless" href="/archives/2018/06/"><span class="level-start"><span class="level-item">六月 2018</span> </span><span class="level-end"><span class="level-item tag">3</span></span></a></li><li><a class="level is-marginless" href="/archives/2017/12/"><span class="level-start"><span class="level-item">十二月 2017</span> </span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-marginless" href="/archives/2017/11/"><span class="level-start"><span class="level-item">十一月 2017</span> </span><span class="level-end"><span class="level-item tag">3</span></span></a></li><li><a class="level is-marginless" href="/archives/2017/10/"><span class="level-start"><span class="level-item">十月 2017</span> </span><span class="level-end"><span class="level-item tag">5</span></span></a></li><li><a class="level is-marginless" href="/archives/2017/09/"><span class="level-start"><span class="level-item">九月 2017</span> </span><span class="level-end"><span class="level-item tag">10</span></span></a></li></ul></div></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">标签</h3><div class="field is-grouped is-grouped-multiline"><div class="control"><a class="tags has-addons" href="/tags/Agile/"><span class="tag">Agile</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Angularjs/"><span class="tag">Angularjs</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Animation/"><span class="tag">Animation</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Application/"><span class="tag">Application</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Artificial-Intelligence/"><span class="tag">Artificial Intelligence</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/BP/"><span class="tag">BP</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Bokeh/"><span class="tag">Bokeh</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Book/"><span class="tag">Book</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/C4-5/"><span class="tag">C4.5</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/CART/"><span class="tag">CART</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/CD/"><span class="tag">CD</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/CLI/"><span class="tag">CLI</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/CSS/"><span class="tag">CSS</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/CentOS/"><span class="tag">CentOS</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Cinder/"><span class="tag">Cinder</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Clipboardjs/"><span class="tag">Clipboardjs</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Concept/"><span class="tag">Concept</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Continuous-Delivery/"><span class="tag">Continuous Delivery</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/DeepLearning/"><span class="tag">DeepLearning</span> <span class="tag is-grey">7</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Department/"><span class="tag">Department</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/DevOps/"><span class="tag">DevOps</span> <span class="tag is-grey">8</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Develop/"><span class="tag">Develop</span> <span class="tag is-grey">4</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Development/"><span class="tag">Development</span> <span class="tag is-grey">16</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Directive/"><span class="tag">Directive</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Distribution/"><span class="tag">Distribution</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Django/"><span class="tag">Django</span> <span class="tag is-grey">3</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Document/"><span class="tag">Document</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/ES5/"><span class="tag">ES5</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/ES6/"><span class="tag">ES6</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Echarts/"><span class="tag">Echarts</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Engine/"><span class="tag">Engine</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Entropy/"><span class="tag">Entropy</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Filter/"><span class="tag">Filter</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Front-End/"><span class="tag">Front End</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Gallery/"><span class="tag">Gallery</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Git/"><span class="tag">Git</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Gradient-descent/"><span class="tag">Gradient descent</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Hexo/"><span class="tag">Hexo</span> <span class="tag is-grey">3</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Horizon/"><span class="tag">Horizon</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/ID3-5/"><span class="tag">ID3.5</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Icarus/"><span class="tag">Icarus</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/JavaScript/"><span class="tag">JavaScript</span> <span class="tag is-grey">9</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Javascript/"><span class="tag">Javascript</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/KVM/"><span class="tag">KVM</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/LaTeX/"><span class="tag">LaTeX</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/LibreOffice/"><span class="tag">LibreOffice</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Linux/"><span class="tag">Linux</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Machine-Learning/"><span class="tag">Machine Learning</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Matrix/"><span class="tag">Matrix</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/MiddleWare/"><span class="tag">MiddleWare</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Module/"><span class="tag">Module</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Network/"><span class="tag">Network</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Nginx/"><span class="tag">Nginx</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/NodeJS/"><span class="tag">NodeJS</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/OOP/"><span class="tag">OOP</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/OpenStack/"><span class="tag">OpenStack</span> <span class="tag is-grey">8</span></a></div><div class="control"><a class="tags has-addons" href="/tags/OpenStackApi/"><span class="tag">OpenStackApi</span> <span class="tag is-grey">5</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Operations/"><span class="tag">Operations</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Oprations/"><span class="tag">Oprations</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/PDF/"><span class="tag">PDF</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Pipline/"><span class="tag">Pipline</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Probability/"><span class="tag">Probability</span> <span class="tag is-grey">3</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Python/"><span class="tag">Python</span> <span class="tag is-grey">6</span></a></div><div class="control"><a class="tags has-addons" href="/tags/React/"><span class="tag">React</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Relational-algebra/"><span class="tag">Relational algebra</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Restful/"><span class="tag">Restful</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Route/"><span class="tag">Route</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/SVD/"><span class="tag">SVD</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/SVM/"><span class="tag">SVM</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Scalar/"><span class="tag">Scalar</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Sigmoid/"><span class="tag">Sigmoid</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Team/"><span class="tag">Team</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Tempest/"><span class="tag">Tempest</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Tensor/"><span class="tag">Tensor</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Testing/"><span class="tag">Testing</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Time/"><span class="tag">Time</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/TimeMachine/"><span class="tag">TimeMachine</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Tips/"><span class="tag">Tips</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Vector/"><span class="tag">Vector</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Vmware/"><span class="tag">Vmware</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Vue/"><span class="tag">Vue</span> <span class="tag is-grey">8</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Vuex/"><span class="tag">Vuex</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/WSGI/"><span class="tag">WSGI</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Web/"><span class="tag">Web</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Word-Cut/"><span class="tag">Word Cut</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/aliyun/"><span class="tag">aliyun</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/auth/"><span class="tag">auth</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/babel/"><span class="tag">babel</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/certbot/"><span class="tag">certbot</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/decision-tree/"><span class="tag">decision tree</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/homebrew/"><span class="tag">homebrew</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/jwt/"><span class="tag">jwt</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/keystone/"><span class="tag">keystone</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/loader/"><span class="tag">loader</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/mathematics/"><span class="tag">mathematics</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/migrate/"><span class="tag">migrate</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/openstack/"><span class="tag">openstack</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/pdf2html/"><span class="tag">pdf2html</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/pm2/"><span class="tag">pm2</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/singular-value-decomposition/"><span class="tag">singular value decomposition</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/vue-router/"><span class="tag">vue-router</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/vue-ssr/"><span class="tag">vue-ssr</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/webpack/"><span class="tag">webpack</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E4%BD%8E%E9%80%9A%E6%BB%A4%E6%B3%A2%E5%99%A8/"><span class="tag">低通滤波器</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%85%A5%E9%97%A8/"><span class="tag">入门</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F/"><span class="tag">全局变量</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1/"><span class="tag">全局对象</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%85%A8%E6%A0%88/"><span class="tag">全栈</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%85%AC%E5%BC%8F/"><span class="tag">公式</span> <span class="tag is-grey">3</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%86%B3%E7%AD%96%E6%A0%91/"><span class="tag">决策树</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%87%BD%E6%95%B0/"><span class="tag">函数</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%88%86%E7%B1%BB%E5%99%A8/"><span class="tag">分类器</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%8A%A0%E9%80%9F/"><span class="tag">加速</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%8C%B9%E9%85%8D%E6%BB%A4%E6%B3%A2%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B/"><span class="tag">匹配滤波边缘检测</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%8D%B7%E7%A7%AF/"><span class="tag">卷积</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%8D%B7%E7%A7%AF%E6%A0%B8/"><span class="tag">卷积核</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%8E%9F%E5%9E%8B%E9%93%BE/"><span class="tag">原型链</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%8F%8D%E5%90%91%E4%BC%A0%E6%92%AD/"><span class="tag">反向传播</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%8F%98%E9%87%8F%E7%B1%BB%E5%9E%8B/"><span class="tag">变量类型</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%AE%98%E6%96%B9%E7%A4%BA%E4%BE%8B/"><span class="tag">官方示例</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%AF%B9%E5%81%B6%E5%BD%A2%E5%BC%8F/"><span class="tag">对偶形式</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%AF%B9%E8%B1%A1/"><span class="tag">对象</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E5%B9%B3%E7%A7%BB%E5%92%8C%E6%9F%A5%E5%88%86%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B/"><span class="tag">平移和查分边缘检测</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%8B%89%E6%A0%BC%E6%9C%97%E6%97%A5%E4%B9%98%E5%AD%90%E6%B3%95/"><span class="tag">拉格朗日乘子法</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%8E%A8%E5%AF%BC/"><span class="tag">推导</span> <span class="tag is-grey">3</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%8F%90%E4%BA%A4%E9%98%B6%E6%AE%B5/"><span class="tag">提交阶段</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%9C%80%E5%A4%A7%E4%BC%BC%E7%84%B6%E4%BC%B0%E8%AE%A1/"><span class="tag">最大似然估计</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E4%BC%B0%E8%AE%A1/"><span class="tag">最小二乘估计</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E6%B3%95/"><span class="tag">最小二乘法</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%9C%B4%E7%B4%A0%E8%B4%9D%E5%8F%B6%E6%96%AF/"><span class="tag">朴素贝叶斯</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"><span class="tag">机器学习</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%9D%A1%E4%BB%B6%E6%A6%82%E7%8E%87/"><span class="tag">条件概率</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D/"><span class="tag">梯度下降</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%A2%AF%E5%BA%A6%E6%96%B9%E5%90%91%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B/"><span class="tag">梯度方向边缘检测</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%A6%82%E5%BF%B5/"><span class="tag">概念</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%A6%82%E7%8E%87/"><span class="tag">概率</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%B1%82%E5%AF%BC/"><span class="tag">求导</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E6%B5%81%E7%A8%8B/"><span class="tag">流程</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E7%86%B5/"><span class="tag">熵</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/"><span class="tag">生命周期</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E7%9F%A9%E9%98%B5/"><span class="tag">矩阵</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"><span class="tag">神经网络</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E7%A7%81%E6%9C%89%E5%AF%B9%E8%B1%A1/"><span class="tag">私有对象</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E7%B1%BB/"><span class="tag">类</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/"><span class="tag">线性回归</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E8%81%94%E5%90%88%E6%A6%82%E7%8E%87/"><span class="tag">联合概率</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E8%B4%9D%E5%8F%B6%E6%96%AF%E5%88%A4%E5%AE%9A%E5%87%86%E5%88%99/"><span class="tag">贝叶斯判定准则</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B/"><span class="tag">边缘检测</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E8%BE%B9%E9%99%85%E6%A6%82%E7%8E%87/"><span class="tag">边际概率</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E9%97%AD%E5%8C%85/"><span class="tag">闭包</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E9%97%B4%E9%9A%94/"><span class="tag">间隔</span> <span class="tag is-grey">2</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E9%AB%98%E6%96%AF%E5%88%86%E5%B8%83/"><span class="tag">高斯分布</span> <span class="tag is-grey">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/%E9%AB%98%E9%80%9A%E6%BB%A4%E6%B3%A2%E5%99%A8/"><span class="tag">高通滤波器</span> <span class="tag is-grey">1</span></a></div></div></div></div></div></div></div></div></div></section><footer class="footer"><div class="container"><div class="level"><div class="level-start has-text-centered-mobile"><a class="footer-logo is-block has-mb-6" href="/"><img src="https://imgs.borgor.cn/imgs20190625111723.jpg" alt="Vuex的基本概念和使用方法" height="28"></a><p class="is-size-7">&copy; 2017-2019 Cyrusky&nbsp; Powered by <a href="https://hexo.io/" target="_blank">Hexo</a> & <a href="https://github.com/ppoffice/hexo-theme-icarus" target="_blank">Icarus</a><br><span id="busuanzi_container_site_uv">共<span id="busuanzi_value_site_uv">0</span>个访客</span><br><a target="_blank" href="https://icp.chinaz.com/info?q=borgor.cn">陇ICP备19002255号</a></p></div><div class="level-end"><div class="field has-addons is-flex-center-mobile has-mt-5-mobile is-flex-wrap is-flex-middle"><p class="control"><a class="button is-white is-large" target="_blank" title="Creative Commons" href="https://creativecommons.org/"><i class="fab fa-creative-commons"></i></a></p><p class="control"><a class="button is-white is-large" target="_blank" title="Attribution 4.0 International" href="https://creativecommons.org/licenses/by/4.0/"><i class="fab fa-creative-commons-by"></i></a></p><p class="control"><a class="button is-white is-large" target="_blank" title="Download on GitHub" href="https://github.com/ppoffice/hexo-theme-icarus"><i class="fab fa-github"></i></a></p></div></div></div></div></footer><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment-with-locales.min.js"></script><script>moment.locale("zh-CN")</script><script src="/js/animation.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/1.6.8/js/lightgallery.min.js" defer></script><script src="https://cdnjs.cloudflare.com/ajax/libs/justifiedGallery/3.7.0/js/jquery.justifiedGallery.min.js" defer></script><script src="/js/gallery.js" defer></script><div id="outdated"><h6>Your browser is out-of-date!</h6><p>Update your browser to view this website correctly. <a id="btnUpdateBrowser" href="http://outdatedbrowser.com/" target="_blank" rel="noopener">Update my browser now</a></p><p class="last"><a href="#" id="btnCloseUpdateBrowser" title="Close">&times;</a></p></div><script src="https://cdnjs.cloudflare.com/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js" defer></script><script>document.addEventListener("DOMContentLoaded",function(){outdatedBrowser({bgColor:"#f25648",color:"#ffffff",lowerThan:"flex"})})</script><script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" defer></script><script>document.addEventListener("DOMContentLoaded",function(){MathJax.Hub.Config({"HTML-CSS":{matchFontHeight:!1},SVG:{matchFontHeight:!1},CommonHTML:{matchFontHeight:!1},tex2jax:{inlineMath:[["$","$"],["\\(","\\)"]]}})})</script><a id="back-to-top" title="回到顶端" href="javascript:;" target="_blank" rel="noopener"><i class="fas fa-chevron-up"></i></a><script src="/js/back-to-top.js" defer></script><script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.4/clipboard.min.js" defer></script><script src="/js/clipboard.js" defer></script><script src="/js/main.js" defer></script><div class="searchbox ins-search"><div class="searchbox-container ins-search-container"><div class="searchbox-input-wrapper"><input type="text" class="searchbox-input ins-search-input" placeholder="想要查找什么..."> <span class="searchbox-close ins-close ins-selectable"><i class="fa fa-times-circle"></i></span></div><div class="searchbox-result-wrapper ins-section-wrapper"><div class="ins-section-container"></div></div></div></div><script>!function(T){var N={TRANSLATION:{POSTS:"文章",PAGES:"页面",CATEGORIES:"分类",TAGS:"标签",UNTITLED:"(无标题)"},CONTENT_URL:"/content.json"};T.INSIGHT_CONFIG=N}(window)</script><script src="/js/insight.js" defer></script><link rel="stylesheet" href="/css/search.css"><link rel="stylesheet" href="/css/insight.css"></body></html><!-- rebuild by neat -->